我们知道,文件是写在磁盘中的,而程序的运行又要借助于内存。那么怎么实现内存和磁盘的“互动”呢?这就要借助“流”来实现了。
内存具体指的就是我们的java程序,而磁盘具体指的是我们的文件。从磁盘到内存叫输入,从内存到磁盘叫输出:
流就相当于一位“外卖小哥”,在内存和磁盘之间来回穿行,携带数据。流有以下几种分类:
字节流 | 字符流 | |
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
如果按照流的角色,还可以分为节点流,处理流/包装流。今天我们要讲的是字节流中的输入流。
字节流适用于所有类型数据,因为它是对数据最底层的操作,直接以字节为单位进行读写的。我们在d盘里创建一个Test97.txt文件并在其中写入“Hello,world”。
我们创建一个文件输入流FileInputStream对象,将文件路径放到其中去,我们的目的是读取到文件中的数据:
String FilePath = "d:\\Test97.txt";
FileInputStream fileInputStream0 = new FileInputStream(FilePath);
我这里创建了一个ArrayList数组list存储数据,并使用read()方法读取数据。注意,read方法一次只能读取一个字节的数据,并且返回值为int类型。当读取完毕时,会返回值-1。
//接收数据
ArrayList<Character>list = new ArrayList<>();
int read0 = 0;
while((read0 = (fileInputStream0.read())) != -1) {list.add((char)read0);
}
创建好一个Character类型的数组,再将接受到的数据进行强制类型转换,放进数组中。
这里为什么我要用read0来接收数据呢?因为如果直接使用fileInputStream0.read()!=-1方法来判断是否接受完毕,再使用list.add((char)fileInputStream0.read());接收数据,实际上总共接受了两次数据,会导致接收的数据错误。
最后需要关闭文件流,释放资源:
fileInputStream0.close();
可以遍历查看数组中的元素是否为我们想要的内容。
read还提供了一种常用的构造方法:read(byte[] b),在read里传入一个byte类型的数组,将文件内容读取到byte类型数组中去,增强了文件读取效率。
这里我们创建另一个FileInputStream对象,并创建一个长度为5的byte类型数组来接受数据:
String FilePath = "d:\\Test97.txt";
FileInputStream fileInputStream1 = new FileInputStream(FilePath);
//创建接受的byte数组
byte[] b = new byte[5];
这里要注意了,读取文件内容的长度最多不超过b.length个字节。超出的字节可以被下一次读取到,但同样不超过b.length个字节。
如果read(byte[] b)方法读取正常,会返回实际读取字节数。
//直接读取
fileInputStream1.read(b);
//释放资源
fileInputStream1.close();
同样可以遍历b数组并强制类型转换来查看是否导入成功:
//转成char类型
for(byte i:b) {System.out.print((char)i);
}
好了,字节输入流就讲到这里,下次我们聊一聊字节输出流。