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 个字节表示一个字符,根据字符的不同变换长度。编码规则如下:
- 对于单个字节的字符,第一位设为 0,后面的 7 位对应这个字符的 Unicode 码点。因此,对于英文中的 0 - 127 号字符,与 ASCII 码完全相同。这意味着 ASCII 码那个年代的文档用 UTF-8 编码打开完全没有问题。
- 对于需要使用 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,就表示该字符占用多少个字节。