Java IO 学习笔记(二)
来源:互联网 发布:易语言如何编程 编辑:程序博客网 时间:2024/05/17 21:58
Java IO 学习笔记(二)
一、文件流
与文件系统的交互是程序的重中之重。在 Java IO 中,我们把与文件系统交互的流称为文件流,它们分别是 FileInputStream 与 FileOutputStream。
在文件流的学习中,有两个问题需要注意:
1. 从广义上来讲,计算机文件即为二进制文件。无论是纯文本文件还是图像文件等,本质上都是以二进制的形式存储在设备中的。
2. Java 的文件流是字节流,只能从文件中读取字节,也只能向文件中写入字节。
二、File
File 类,即为文件类,它以抽象的方式代表文件名和目录路径名,主要用于文件和目录的创建、文件的查找和文件的删除等。
无论是 FileInputStream 还是 FileOutputStream,都依赖于 File 类。它们都需要通过 File 对象,来对磁盘中实际存在的文件进行操作。
本文重点要介绍的是 IO 操作,因此对于 File 类不做深入讨论,如有兴趣进一步了解,可自行阅读源码或者阅读以下基础教程:Java File 类
三、FileInputStream
FileInputStream 是 Java 文件流中的输入流,继承自 InputStream,可以从本地文件系统中读取字节数据。
3.1 类图
3.2 构造方法
如上图所示,FileInputStream 有 3 种构造方法:
3.3 方法详解
从类图中可以看出,FileInputStream 的方法并不少。但实际上,开发人员只要重点掌握以下几个方法即可。
3.4 应用实例
首先,我们在项目源目录下创建文本文件 panda.txt
,并在该文件中输入 4 个字符 abcd
。
然后,我们使用 FileInputStream 尝试读取 panda.txt
的数据。
private static final String FILE_PATH = FileUtil.class.getClassLoader().getResource("").getPath();public static void readFile() { File file = new File(FILE_PATH + File.separator + "panda.txt"); try { InputStream in = new FileInputStream(file); int len; while ((len = in.read()) != -1) { System.out.println(len); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }}
代码编写完后,点击运行,发现控制台打印出如下结果:97 98 99 100
。
这时候我们就遇到一个问题了。为什么我们输入的是 abcd
,结果 FileInputStream 读到的却是这 4 个数字?
答案就在下面这张表格,也是著名的 ASCII 码表的一部分。
我们一再强调,FileInputStream 是字节流,只能从文件中读取字节。因此,当你的文本文件中含有字符 a
时,FileInputStream 所获取的实际上是字符 a
在存储空间中所代表的二进制数据 0110 0001
,然后再以十进制的形式返回到我们的控制台上。
这时候我们又碰到了一个问题。如果以上论述成立的话,那么,字符与二进制之间的关系是如何确立的?
这个问题,就需要编码来解决了。在我们本例中,因为文本文件中存储的是英文字母,所以只需要 ASCII 码表就够了。但假如文本文件中含有中文呢?结果又会是怎样?
现在,我们将 panda.txt
中的数据改为 一
,然后再次运行程序,得到以下结果:228 184 128
。
wtf?我输入的是汉字,你给我的是什么玩意?实际上,这三个数字是由 UTF-8 编码将汉字 一
转化成字节数据的结果。如果此时我们将 panda.txt
的编码格式改为 GBK,会发现程序的运行结果如下:210 187
。
我们可以看到,在 UTF-8 编码中,汉字 一
占据了 3 个字节,而在 GBK 编码中,汉字 一
仅占据了 2 个字节。
综上,我们可以做如下结论:FileInputStream 只能读取字节,而字节的值,是由编码方式与字符集决定的。
四、FileOutputStream
FileOutputStream 是 Java 文件流中的输出流,继承自 OutputStream,可以向本地文件系统写入字节数据。
4.1 类图
4.2 构造方法
如上图所示,FileOutputStream 有 5 种构造方法:
4.3 方法详解
相对 FileInputStream,FileOutputStream 的方法数量会少一些,常用的方法如下表所示。
4.4 应用实例
首先,我们完成一个 FileOutputStream 的代码实例。
public static void writeFile() { File file = new File(FILE_PATH + File.separator + "out.txt"); try { OutputStream out = new FileOutputStream(file); out.write(97); out.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }}
然后我们打开 out.txt
文件,发现里面有一个字符 a
。但是,我们注意到,代码里面 write(int b) 方法的参数明明是 97 啊,为什么会变成字符 a
了?还是跟我们在 FileInputStream 中的解释一样。 FileOutputStream 只能写出字节数据! 所以你给了它一个值为 97 的参数,它不会明白 97 的意思,但是它能找到 97 对应的字符 a
。
我们再来做一件有趣的事情,试一试写入代表中文字符的字节。
public static void writeFile() { File file = new File(FILE_PATH + File.separator + "out.txt"); try { OutputStream out = new FileOutputStream(file); String text = "一"; out.write(text.getBytes()); out.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }}
因为 FileOutputStream 不能直接写入字符串,因此我们需要调用 String 类的 getBytes() 方法,获取字节数组。
点击运行程序后,我们打开 out.txt
文件,发现里面确实写入了字符 一
。
嗯,看样子我们像是已经完成了 FileOutputStream 的学习,但是别急,我们还有一件事没做。
首先,我们查看了 out.txt
的编码,发现编码方式为 UTF-8
。这时候问题来了,我们什么时候指定编码方式了?仔细思考一下,应该是在调用 getBytes() 方法时实现了编码的设置,因此我们从 getBytes() 方法跟踪进去,最后在 Charset 类中发现了下面的代码:
public static Charset defaultCharset() { if (defaultCharset == null) { synchronized (Charset.class) { String csn = AccessController.doPrivileged( new GetPropertyAction("file.encoding")); Charset cs = lookup(csn); if (cs != null) defaultCharset = cs; else defaultCharset = forName("UTF-8"); } } return defaultCharset;}
这段代码有什么作用呢?它可以返回 JVM 的默认编码格式,而 JVM 的编码格式,又依赖于底层操作系统。因为我的系统使用的是 UTF-8
编码,因此我们在运行上面的示例代码时,默认使用了 UTF-8
。
当然,这个编码方式我们也可以自己指定。
public static void writeFile() { File file = new File(FILE_PATH + File.separator + "out.txt"); try { OutputStream out = new FileOutputStream(file); String text = "一"; out.write(text.getBytes("GBK")); out.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }}
点击运行后,我们使用 Binary Viewer 查看 out.txt
文件,发现里面有两个字节,值为 210 187
,刚好与我们在 FileInputStream 中的示例一致。
综上,我们可以做如下结论:FileOutputStream 只能输出字节,而字节的编码方式,可以用户自己设置,也可以使用 JVM 的默认编码。
写在最后:实际上,目前需要程序直接做文本输入输出的情况已经非常少了,大多数情况,我们可以选择使用更为专业的 Property 工具类。但是,我们还是有必要深入学习文本的输入与输出,特别是其中涉及的编码与解码。只有这部分的基础牢固了,才能在日后的开发中避免乱码的发生。
- Java IO 学习笔记(二)
- Java IO学习笔记二
- java学习笔记(二十六)java中的io流
- IO学习笔记(二)
- 黑马程序员-Java学习笔记之IO流(二)
- Java IO流 学习笔记(二)PrintStream
- Java IO学习笔记(二):RandomAccessFile类
- java IO流学习笔记二
- IO学习笔记(二)
- 黑马程序员--学习笔记(IO二)
- 字节流--IO学习笔记(二)
- Java文件IO学习笔记(二)---文件锁定
- Java学习笔记之IO(二):InputStream输入字节流
- Java IO学习笔记
- Java IO学习笔记
- java IO学习笔记
- Java IO学习笔记
- Java IO学习笔记
- JavaScript 使用对象及ES6中的class
- 移动端Click300毫秒点击延迟
- 几个常用线程的
- 学生管理系统优化总结(一)
- 文字检测与识别资源
- Java IO 学习笔记(二)
- javaWeb-EL表达式和JSTL
- Merkle Tree学习
- Work Scheduling URAL
- python爬虫之post请求
- iconfont
- 数据库事务隔离
- 笔试_oracle(2)
- MVP