深入理解Java IO流:字节流
引言
在Java中,IO(输入/输出)操作是程序与外部世界交互的重要方式。
其中,File类是进行文件操作的基础,而字节流和字符流则是数据传输的两种主要方式。
本文将深入探讨这些概念及其应用。
一、 字节流类详解:
- I0流介绍以及输入输出以及流向的介绍:
- Output :输出
- Input: 输入
- write:写数据
- read:读数据
插曲:取 Output 和 Input 单词首字母不就是 IO 吗?
- IO流 :
- 将一个设备上的数据传输到另外一个设备上,称之为 IO 流技术
二、 IO流向(Java基础阶段IO):
输入:内存 —— Output(将内存中的数据写到硬盘中)> 硬盘
输出:硬盘——Input(将硬盘中的数据读取到内存中)> 内存
如不理解,可以把自己比做内存,当我们吃饭喝水时是输入Input 输入
,上厕所时是 Output 输出
- 网络层面来说输出输入(简单理解):
- 发数据–> 方:输出
- 接数据–> 方:输入
三、 IO流向分类:
- 字节流:万能流,一切皆字节(数据在存储的最小单元是字节)
- 字节输出流:0utputstream 抽象类
- 字节输入流:Inputstream 抽象类
- 字符流:专门操作文本文档
- 字符输出流:Write 抽象类
- 字符输入流:Read 抽象类
四、字节输出流:
1、OutputStream中子类FileOutputStream
使用:
- 概述:字节输出流,OutputStream是一个抽象类
- 子类:FileOutputStream
- 作用:往硬盘上写数据
- 构造:
- Fileoutputstream(File file)
- Fileoutputstream(String name)
- 特点:
- 指定的文件如果没存在,输出流会自动创建
- 每次执行,默认都会创建一个新的文件,覆盖老文件
- 方法:
- void write(int b) 一次写一个字节
- void write(byte[] b) 一次写一组字节
- void write(byte[] b,int off ,int len) 一次写部分字节
- b:写的数组
- off:从数组那个位置开始写
- len:一次写多少
- void close() 关闭资源
- 测试测试
public static void main(String[] args) throws FileNotFoundException {
FileOutputStream fos = new FileOutputStream("testfile.txt");
}
- 使用方法 wrtie
- 在下述案例中我们使用 wrtie 方法写入一个 98 ,这个 98 是字节
- 当我们打开 testfile 文件时会自动对 98这个字节进行翻译成我们人能看得懂的内容,就是 b
- 而这个翻译是按照 ASCll 表进行翻译的
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("testfile.txt");
//fos.write(98);
String data = "sha bi go pe";
byte[] bytes = data.getBytes();
//fos.write(bytes); // 一次写一个数字
fos.write(bytes,0,3); // 一次写一个数组一部分
}
- 一次写一个数组
- 一次写一部分
2、OutputStream中子类FileOutputStream
的续写(最加):
- 构造:
- Fileoutputstream(String name,boolean append)
- append:true 最加内容
- Fileoutputstream(String name,boolean append)
- 换行:
- windows : \r\n 或者 \n
- Linxu:\n
- mac os :\r
public static void main(String[] args) throws IOException {
// FileOutputStream fos = new FileOutputStream("testfile.txt");
// fos.write(98);
// String data = "sha bi go pe";
// byte[] bytes = data.getBytes();
//fos.write(bytes); // 一次写一个数字
// fos.write(bytes,0,3); // 一次写一个数组一部分
FileOutputStream fos = new FileOutputStream("testfile.txt",true);
fos.write("干就完了,打工人".getBytes());
fos.close();
}
五、字节输入流:
- 概述:字节输入流:inputStream ,抽象类
- 子类:FileInputStream
- 作用:读数据,将数据从硬盘上读取到内存中
- 构造:
- FileInputstream(File file)
- FileInputstream(String name)
- 注意:FileInputstream 没有自动创建功能,以为它是读取已经存在的文件
- 方法:
- void read(int b) 一次读一个字节,返回数据为字节
- void read(byte[] b) 一次读一组字节,返回字节个数
- void read(byte[] b,int off ,int len) 一次读部分字节
- void close() 关闭资源
- 测试测试
- 小细节
- 问题0:读到 -1 ,表示文件有效的内容,已经全部读取完毕
- 每一个文件末尾都有一个
结束标记
,这个结束标记
我们看不见 - 而
read()
方法规定了,如读取到了文件的结束标记,方法返回 -1
- 每一个文件末尾都有一个
- 问题1:一个流对象,读完之后,就不要再读了;除非重新new一个新的对象
- 问题2:流关闭之后,流对象不能继续使用了
- 问题0:读到 -1 ,表示文件有效的内容,已经全部读取完毕
// 一次读取一个字节
@Test
public void InputStream() throws IOException {
FileInputStream fileInputStream = new FileInputStream("testfile.txt");
int read = fileInputStream.read(); // 一次读一个字节
System.out.println(read);
System.out.println(fileInputStream.read());
// 读到 -1 ,表示文件有效的内容,已经全部读取完毕
System.out.println(fileInputStream.read());
System.out.println(fileInputStream.read());
fileInputStream.close();
}
// 循环读取
@Test
public void InputStream2() throws IOException {
FileInputStream fileInputStream = new FileInputStream("testfile.txt");
// 循环读取
int i;
while ((i = fileInputStream.read()) != -1){
System.out.println(i);
}
fileInputStream.close();
}
@Test
public void InputStream3() throws IOException {
FileInputStream fileInputStream = new FileInputStream("testfile.txt");
/**
*
* 创建一个数组,用于临时存储区域,我们要读取的内容会临时存储到数组中
*
* 数组的长度对少,每次就读取多少,一般情况是 1024 或者 1024 的倍数
* 如果剩下的字节不够数组长度,那么有多少读取多少
* */
byte[] bytes = new byte[2];
int i;
while ((i = fileInputStream.read(bytes)) != -1){
String s = new String(bytes, 0, i);
System.out.println(s);
}
fileInputStream.close();
}
六、练习:
1、复制文件
@Test
public void InputStream4() throws IOException {
// 要被复制的文件夹
String file = "D:\\a";
// 复制玩后,粘贴的位置
String deposit = "D:\\b";
method(file, deposit);
}
public static void method(String file, String deposit) throws IOException {
File sourceFile = new File(file);
File[] files = sourceFile.listFiles();
if (files == null) throw new IOException("目录不可访问: " + sourceFile);
for (File sourceFileItem : files) {
File destinationFileItem = new File(deposit, sourceFileItem.getName());
if (sourceFileItem.isFile()) {
try (
// 读(输入)
FileInputStream fileInputStream = new FileInputStream(sourceFileItem);
// 写(输出)
FileOutputStream fileOutputStream = new FileOutputStream(destinationFileItem)
)
{
int len;
byte[] bytes = new byte[1024];
while ((len = fileInputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, len);
}
}
} else if (sourceFileItem.isDirectory()) {
// 确保目标目录存在
destinationFileItem.mkdirs();
// 子目录的递归调用
method(sourceFileItem.getAbsolutePath(), destinationFileItem.getAbsolutePath());
}
}
}