3、文本输入输出

在保存数据时,可以选择二进制格式或文本格式。

例如,整数1234存储成二进制数时,他被写成

01 02 03 04

构成的序列(十六进制表示法),而存成文本格式时,他被存成了“1234”字符串。

尽管二进制格式的IO高速高效,但是不利于人来阅读。

在存储文本字符串时,需要考虑字符编码(character encoding)方式。

    public static void main(String[] args) throws IOException {
        File file = new File("D:\\workspace\\test\\test.txt");
        FileInputStream fin = new FileInputStream(file);
        Reader in = new InputStreamReader(fin, StandardCharsets.UTF_8);
        while(true){
            int c =in.read();
            if(c ==-1){
                break;
            }
            System.out.println(">>>>>>>>>>>>");
            System.out.println((char)c);
        }

    }

上述代码只有utf-8 BOM格式的才正常显示。

1、写文本输出

PrintWriter 这个类拥有以文本格式打印字符串和数字的方法,它还有一个将PrintWriter链接到FileWriter的便捷方法。

public static void main(String[] args) throws IOException {
    File file = new File("D:\\workspace\\test\\data.txt");
    FileWriter fout = new FileWriter(file,true);
    PrintWriter out = new PrintWriter(fout,true);
    out.println("abc=123");
    double salary =172.55;
    out.println(salary);
    out.close();
}

java.io.PrintWriter

方法 参数 说明
public PrintWriter (Writer out) out 创建一个向给定的写出器写出的新的PrintWriter
public PrintWriter(OutputStream out) out 创建一个向给定的写出器写出的新的PrintWriter
public PrintWriter(String fileName, Charset charset) throws IOException
public PrintWriter(File file, Charset charset) throws IOException
public void print(Object obj)
public void print(String s)
public void print(char s[])
public void print(char c)
public void write(int c)
public void write(String s)
public PrintWriter printf(String format, Object ... args) format 这个打印还具有格式化的能力
out.printf("主机%s共有%d台", "dgg522", 10);  // 是不是看到日志输出的秘密

2、如何读入文本输入

2.1、scanner类

public static void main(String[] args) throws IOException {
    Scanner scanner = new Scanner(new FileInputStream("D:\\workspace\\test\\data.txt"));
    while (scanner.hasNextLine()) {
        System.out.println(scanner.nextLine());
    }
}

2.2、Files.readAllBytes(path)

这个只能适用于小文件,一次性读入内存

Files 让Java对小文件的操作变的简单,这个可以进行认真研究下

    public static void main(String[] args) throws IOException {
        String content =Files.readString(Paths.get("D:\\workspace\\test\\test.txt"));
        System.out.println(content);

    }

2.3、Files.readAllLines逐行读入

public static void main(String[] args) throws IOException {
    List<String> stringList = Files.readAllLines(Paths.get("D:\\workspace\\test\\test.txt"));
    stringList.stream().forEach(elemet -> {
        System.out.println(elemet);
    });
}

2.4、传统的BufferedReader类

public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader("D:\\workspace\\test\\test.txt"));
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
}

3、编码方式

字节序列不涉及编码方式,但是很多时候我们希望操作的是文本,即字符序列。

字符如何编码成字节,就成了最让人头痛的问题。

Java针对字符使用的是Unicode标准,而标准格式选用的utf-8.

Unicode字符集只是为每个字符分配一个唯一ID。

而如何通过字节表示这些ID,则涉及到Unicode的编码。

Unicode的编码方案有多个,目前常见的Unicode编码方案包括UTF-8、UTF-16、UTF-32等,都是将数字转换到程序数据的编码方案。

其中,又以UTF-8最为常用。

UTF-8是以一个字节为单位对Unicode进行编码。

UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,又称万国码,由Ken Thompson于1992年创建。

需要注意的是,UTF-8是可变长度的字符编码,UTF-8用1-4个字节编码Unicode字符,是一种不定长的编码方案。

UTF-8 是一个非常惊艳的编码方式,漂亮的实现了对 ASCII 码的向后兼容,以保证 Unicode 可以被大众接受。

UTF-8 是目前互联网上使用最广泛的一种 Unicode 编码方式,它的最大特点就是可变长。它可以使用 1 - 4 个字节表示一个字符,根据字符的不同变换长度。编码规则如下:

  1. 对于单个字节的字符,第一位设为 0,后面的 7 位对应这个字符的 Unicode 码点。因此,对于英文中的 0 - 127 号字符,与 ASCII 码完全相同。这意味着 ASCII 码那个年代的文档用 UTF-8 编码打开完全没有问题。
  2. 对于需要使用 N 个字节来表示的字符(N > 1),第一个字节的前 N 位都设为 1,第 N + 1 位设为0,剩余的 N - 1 个字节的前两位都设位 10,剩下的二进制位则使用这个字符的 Unicode 码点来填充。

编码规则如下:

Unicode 十六进制码点范围 UTF-8 二进制
0000 0000 - 0000 007F 0xxxxxxx
0000 0080 - 0000 07FF 110xxxxx 10xxxxxx
0000 0800 - 0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000 - 0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

根据上面编码规则对照表,进行 UTF-8 编码和解码就简单多了。下面以汉字“汉”为利,具体说明如何进行 UTF-8 编码和解码。

“汉”的 Unicode 码点是 0x6c49(110 1100 0100 1001),通过上面的对照表可以发现,0x0000 6c49 位于第三行的范围,那么得出其格式为 1110xxxx 10xxxxxx 10xxxxxx。接着,从“汉”的二进制数最后一位开始,从后向前依次填充对应格式中的 x,多出的 x 用 0 补上。这样,就得到了“汉”的 UTF-8 编码为 11100110 10110001 10001001,转换成十六进制就是 0xE6 0xB7 0x89

解码的过程也十分简单:如果一个字节的第一位是 0 ,则说明这个字节对应一个字符;如果一个字节的第一位1,那么连续有多少个 1,就表示该字符占用多少个字节。

posted @ 2022-09-18 22:59  红尘过客2022  阅读(130)  评论(0编辑  收藏  举报