Java——I/O(字符编码、内存流、打印流、System、输入流、序列化)

1.常见的编码

 GBK、GB2312:国标编码,GBK包含简体中文和繁体中文,而GB2312只包含简体中文。

UNICODE编码:java提供的16进制编码,可以描述世界上任意的文字信息。由于使用16进制编码,编码体积太大,造成网络传输的负担。

ISO8859-1:国际通用编码,不支持中文。(浏览器默认编码)

UTF编码:相当于结合了UNICODE、ISO8859-1,支持所有语言且体积较小,常用的就是UTF-8编码形式。 

2.乱码产生原因

95%的乱码产生于编解码不一致

读取java运行属性

import java.io.*;
import java.nio.file.Paths;

/**
 * 乱码的产生
 * Author: qqy
 */
public class Test {
    public static void main(String[] args) {
        File file=Paths.get("E:","JAVA","Test.txt").toFile();
        try( FileOutputStream out=new FileOutputStream(file);
        ) {
            //统一采用UTF-8
           out.write("你好hello".getBytes("ISO-8859-1"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3.内存流

除了文件之外,IO的操作也可以发生在内存之中。发生在内存中的操作流称为内存操作流。

  • 3.1 分类:

字节内存流:ByteArrayInputStream、ByteArrayOutputStream(输出无参数)

字符内存流:CharArrayReader、CharArrayWriter

  • 3.2应用

  • 内存流实现字母转换
import java.io.*;

/**
 * 内存流应用
 * Author: qqy
 */
public class Test {
    public static void main(String[] args) {
        //方法一:
        String msg="hello";
        //取得内存流
        ByteArrayInputStream inputStream=new ByteArrayInputStream(msg.getBytes());
        ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
        int len=-1;
        while((len=inputStream.read())!=-1){
            outputStream.write(Character.toUpperCase(len));
        }
        //直接将内存输出流输出
        System.out.println(outputStream);
        //方法二:
        try(InputStream in = new ByteArrayInputStream(msg.getBytes());
            OutputStream out = new ByteArrayOutputStream()//默认构造方法缓存区32个字节(32)
        ){
            byte[] buff=new byte[3];
            int count=0;
            while((len=in.read(buff))!=-1) {
                for (int i = 0; i < len; i++) {
                    byte b=buff[i];
                    if(b>='a'&&b<='z') {
                        count++;
                        buff[i] = (byte) (buff[i] - 32);
                    }
                }
                out.write(buff,0,len);
            }
            //OutputStream中没有toByteArray,当前情况下要使用必须向下转型
            byte[] newData= ((ByteArrayOutputStream) out).toByteArray();
            System.out.println(new String(newData));
            System.out.println("转换次数:"+count);
        }catch (IOException e){

        }
    }
}
  • 文件合并(考虑到内存,文件不宜过大)
import java.io.*;
import java.nio.file.Paths;

/**
 * 内存流合并两个文件(代码量重复过多)
 * Author: qqy
 */
public class Test1 {
    public static void main(String[] args) {
        File file1=Paths.get("E:","JAVA","Test.txt").toFile();
        File file2=Paths.get("E:","JAVA","Test1.txt").toFile();
        //目标文件
        File file3=Paths.get("E:","JAVA","destTest.txt").toFile();

        try(FileInputStream in1=new FileInputStream(file1);
            FileInputStream in2=new FileInputStream(file2);
            ByteArrayOutputStream memoryOut=new ByteArrayOutputStream();
            FileOutputStream out=new FileOutputStream(file3);
        ){
            //读文件并写入内存流
            byte[] buff=new byte[5];
            int len=-1;
            while((len=in1.read(buff))!=-1){
                memoryOut.write(buff,0,len);
            }
            while((len=in2.read(buff))!=-1){
                memoryOut.write(buff,0,len);
            }
            //写入文件
            out.write(memoryOut.toByteArray());
        }catch (IOException e){

        }
    }
}

优化后:

import java.io.*;
import java.nio.file.Paths;

/**
 * 内存流合并两个文件(代码量重复过多)
 * Author: qqy
 */
public class Test1 {
    public static void main(String[] args) {
        File file1=Paths.get("E:","JAVA","Test.txt").toFile();
        mergeFileBetter(new String[]{
                "E:"+File.separator+"JAVA"+File.separator+"Test.txt",
                "E:"+File.separator+"JAVA"+File.separator+"Test1.txt"
        },"E:"+File.separator+"JAVA"+File.separator+"destTest.txt");
    }

    public static void mergeFileBetter(String[] mergePaths,String outPaths){
        //参数校验
        File[] files=new File[mergePaths.length];
        //初始化所有输入文件
        for(int i=0;i<mergePaths.length;i++){
            files[i]=new File(mergePaths[i]);
        }
        //输出流
        try(ByteArrayOutputStream memoryOut=new ByteArrayOutputStream();
            FileOutputStream out=new FileOutputStream(outPaths)
        ) {
            //遍历合并的文件,输入到内存流
            for (File f : files) {
                try (FileInputStream in = new FileInputStream(f)) {
                    //读文件并写入内存流
                    byte[] buff=new byte[3];
                    int len=-1;
                    while((len=in.read(buff))!=-1){
                        memoryOut.write(buff,0,len);
                    }
                } catch (IOException e) {

                }
            }
            //内存流输出到文件
            out.write(memoryOut.toByteArray());
        }catch (IOException e){

        }
    }
}

4.打印流

输出流的进化版

扫描二维码关注公众号,回复: 4528560 查看本文章
  •  4.1 自定义打印流:

import java.io.*;
import java.nio.file.Paths;

/**
 * 设计打印流
 * Author: qqy
 */
public class DesignPrintStream {
    public static void main(String[] args) {
        //DesignPrintStream print = new DesignPrintStream(System.out);
        DesignPrintStream print =null;
        try {
            print = new DesignPrintStream(
                    new FileOutputStream(Paths.get("E:","JAVA","Test.txt").toFile())
            );
            print.println("Hello");
            print.println(10);
            print.println(10.0d);
            print.println(true);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    private OutputStream outputStream;

    public DesignPrintStream(OutputStream outputStream){
        this.outputStream=outputStream;
    }

    public void print(String str){
        try {
            //核心在于OutputStream提供的write
            outputStream.write(str.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void println(String str){
        print(str+"\r\n");
    }

    public void println(int value){
        println(String.valueOf(value));
    }

    public void println(double value){
        println(String.valueOf(value));
    }

    public void println(boolean value){
        println(String.valueOf(value));
    }
}
  • 4.2 系统提供的打印流

字节打印流:PrintStream         字符打印流:PrintWriter

  • 打印流应用的是装饰设计模式(基于抽象类):核心依然是某个类(OutputSream)的功能(write()),但是为了得到更好的操作效果,让其支持的功能更多。
  • 优点:扩展功能方便,需要不同的功能时只需要更换装饰类即可。           缺点:类结构复杂

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.nio.file.Paths;

/**
 * Author: qqy
 */
public class Test {
    public static void main(String[] args) {
        PrintStream print =null;
        try {
            print = new PrintStream(
                    new FileOutputStream(Paths.get("E:","JAVA","Test.txt").toFile())
            );
            print.println("Hello");
            print.println(10);
            print.println(10.0d);
            print.println(true);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}
  • 4.3 格式化输出

public PrintStream printf(String format, Object ... args)
  • 简答:

System是类(java.lang.System)

out / err 是对象(PrintStream的属性,java.io.PrintStream)/ in是对象(java.io.InputStream)

println是PrintStream类的成员方法,out对象的方法 / read是InputStream类的成员方法,in对象的方法

/**
 * Author: qqy
 */
public class TestFormat {
    public static void main(String[] args) {
        System.out.printf("%s","bonjour");
        System.out.printf("姓名:%s,年龄:%d,身高:%.2f","李四",18,180.6);
        System.out.println();
        //正:右对齐,负:左对齐
        System.out.printf("姓名:%4s\n年龄:%-4d\n身高:%8.2f\n","张三",25,168.8);
        //java.util.Formatter
        //String.format,System.out.printf用法一直
        String str=String.format("姓名:%s\n年龄:%d\n身高:%.2f\n","张三",25,168.8);
        //System是类,out是对象,
        System.out.println(str);
    }
}

5.System对I/O的支持

  • 输出:均是打印流PrintStream的对象

标准输出——显示器   System.out

错误输出——System.err

  • 输入:输入流InputStream的对象

标准输入——键盘       System.in

标准输出:

public class Test {
    public static void main(String[] args) {
        try{
            //让OutputStream的输出位置变为屏幕
            OutputStream out=System.out;
            out.write("hello\n".getBytes());
            System.err.println("bonjour");
            Integer.parseInt("123aaa");
        }catch (NumberFormatException e){
            System.out.println(e.getMessage());
            System.err.println(e.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

标准输入:

有限制:

import java.io.IOException;
import java.io.InputStream;

/**
 * Author: qqy
 */
public class Test1 {
    public static void main(String[] args) throws IOException {
        //从键盘输入
        InputStream in=System.in;
        //数组长度固定,可能无法读取全部内容
        byte[] data=new byte[6];
        System.out.println("请输入内容:");
        int len=in.read(data);
        System.out.println(new String(data,0,len));
    }
}

优化:

import java.io.*;

/**
 * Author: qqy
 */
public class Test3 {
    public static void main(String[] args) {
        InputStream in=System.in;
        byte[] buff=new byte[5];
        System.out.println("请输入内容:");
        int len=-1;
        //利用内存流消除限制
        try(ByteArrayOutputStream out=new ByteArrayOutputStream()){
            while((len=in.read(buff))!=-1){
                out.write(buff,0,len);
                //当读取的长度数组的长度,则读取完成,跳出循环
                if(len<buff.length){
                    break;
                }
            }
            System.out.println(new String(out.toByteArray()));
        }catch (IOException e){
            System.out.println(e.getMessage());
        }
    }
}

6.两种输入流

原生InputStream的进化版

  • 6.1 BufferedReader(了解)

——readLine() 读取一行输入

import java.io.*;

/**
 * 利用BufferedReader实现键盘输入
 * Author: qqy
 */
public class Test4 {
    public static void main(String[] args) {
        //BufferedReader->InputStreamReader->InputStream
        try( InputStream inputStream=System.in;
             InputStreamReader inputStreamReader=new InputStreamReader(inputStream);
             BufferedReader reader=new BufferedReader(inputStreamReader)
        ){
            String line;
            System.out.println("请输入内容:");
            while(!(line=reader.readLine()).equals("q")){
                System.out.println(line);
            }
        }catch(IOException e){
            System.out.println(e.getMessage());
        }
    }
}
  • 6.2 Scanner(java.util.Scanner)

  1. 判断是否有指定类型数据输入: public boolean hasNextXXX()
  2. 取得指定类型的数据: public 数据类型 nextXXX()
  3. 自定义分隔符:public Scanner useDelimiter(Pattern pattern)
  4. 构造方法:public Scanner(InputStream source) 
  • 输出使用打印流,输入使用Scanner类

Scanner读取数据:

import java.util.Scanner;

/**
 * Scanner读取数据
 * Author: qqy
 */
public class Test2 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入内容:");
        //判断是否有内容
        if (scanner.hasNext()) {
            //输出输入的内容(空格被忽略)
            System.out.println(scanner.next());
        }
        while (true) {
            System.out.println("请输入年龄:");
            if (scanner.hasNextInt()) {
                System.out.println("年龄是:" + scanner.nextInt());
                break;
            } else {
                System.out.println("您输入的格式有误,请重新输入:");
                scanner.next();//丢弃不符合要求的数据
            }
        }
        System.out.println("请输入出生日期:");
        //正则表达式 d——整数  数字——长度
        if (scanner.hasNext("\\d{4}-\\d{2}-\\d{2}")) {
            System.out.println(scanner.next());
        }
    }
}

Scanner读取文件:

import java.io.IOException;
import java.nio.file.Paths;
import java.util.Scanner;

/**
 * Scanner读取文件
 * Author: qqy
 */
public class Test5 {
    public static void main(String[] args) {
        try (Scanner scanner=new Scanner(Paths.get("E:","JAVA","Test.txt"))){
           while(scanner.hasNext()){
               //声明文件的分隔符是\n
               scanner.useDelimiter("\n");
               System.out.println(scanner.next());
           }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

System 拓展:

1.系统属性

import java.util.Properties;

/**
 * 系统属性
 * Author: qqy
 */
public class Test6 {
    public static void main(String[] args) {
        //系统属性
        Properties properties=System.getProperties();

        //常用系统属性
        //user.home / user.dir / java.home / path.separator / file.separator

        //获取用户目录
        String userHome=(String)properties.get("user.home");
        System.out.println(userHome);
    }
}

2.系统环境变量

import java.io.File;
import java.nio.file.Paths;
import java.util.Map;

/**
 * 系统环境变量
 * Author: qqy
 */
public class Test7 {
    public static void main(String[] args) {
        //返回Map接口的实例化对象
        Map<String, String> env = System.getenv();
        for (Map.Entry<String, String> entry : env.entrySet()) {
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }

        //JAVA_HOME    配置的环境变量
        //SystemDrive  获取驱动盘
        //Path
        //ProgramData  存放数据
        //ProgramW6432 获取安装目录
        //TEMP         临时目录
        //NUMBER_OF_PROCESSORS  处理器的核数
        System.out.println(System.getenv("JAVA_HOME"));
        
        //将文件写入临时目录
        File tempFile = Paths.get(
                System.getenv("TEMP"),
                "abc.txt")
                .toFile();

        System.out.println(tempFile.getAbsolutePath());
    }
}

7.序列化

将内存中的对象变为二进制数据流的形式进行传输或保存于文本中。

  • 7.1 初识

        1.Java提供的一种序列化(JDK提供) 远程方法调用(RPC)

序列化:将内存转换为字节数组,可在网络中传输,保存文件

               Object(In Memory) -> byte[]

反序列化:

               byte[] -> Object(In Memory)

        2. Object  -> JSON (前端开发 JavaScript) Person(name,age) -> {"name":"Jack", "age": 22}

               JSON    -> Object

        3. Object -> XML (XML文件——可扩展的标志语言)(JDK提供)

               XML    -> Object

       4.Java序列化:

序列化对象的属性信息

反序列化不会执行构造方法和构造块

  • 7.2 实现

Java中的类如果要被序列化输出,该类必须实现Serializable接口,该接口是一个标识接口,表示该类具有序列化的功能。

  • 7.3 序列化与反序列化操作:

要想实现序列化与反序列化的对象操作,需要使用java.io包中提供的两个类:ObjectOutputStream、 ObjectInputStream

对象序列化输出—ObjectOutputStream          对象反序列化输入—ObjectInputStream

  • 将对象序列化输出方法:
 public final void writeObject(Object obj) throws IOException
  • 将对象反序列化输入方法:
  public final Object readObject() throws IOException, ClassNotFoundException
  • 使用Serializable序列化输出时,默认将对象的所有属性以及值均序列化以及反序列化。若希望某些属性值不进行序列化输出,可以在属性前加transient关键字

代码示例:

import java.io.*;
import java.nio.file.Paths;

/**
 * Author: qqy
 */
public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        File file=Paths.get("E:","JAVA","Test.txt").toFile();
        //取得相应输出流
        Person1 per=new Person1("张三",18);
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(file));
        //数据序列化输出
        oos.writeObject(per);
        oos.close();

        ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file));
        //数据反序列化输入
        Object res=ois.readObject();
        System.out.println(res);  //Person{name=张三 age=0"}
        ois.close();
    }
}

//Serializable  标识接口
class Person1 implements Serializable{
    private String name;
    private transient int age;

    public Person1(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name=" + name +
                " age=" + age +
                "\"}";
    }
}

 

猜你喜欢

转载自blog.csdn.net/qq_42142477/article/details/84927860