Java——IO流
目录
前言:
在 Java 程序设计中,IO(Input/Output)流是一项至关重要的功能,它允许程序与外部世界进行数据的交换。无论是从文件中读取数据,将数据写入文件,还是通过网络进行通信,IO 流都扮演着核心角色。理解和掌握 Java 的 IO 流机制对于开发强大、可靠和高效的应用程序是必不可少的。本章节将带你深入探索 Java IO 流的奥秘,从基础概念开始,逐步深入到各种类型的 IO 流及其实际应用,帮助你轻松应对不同场景下的数据输入和输出需求。
IO流的体系总览
一、 字节流:
1.1:写数据(FileOutputStream):
写出一段文字到本地文件当中
FileOutputStream()形参可以是字符串也可以是file对象
1.1.1:写单个字符或数组
1.先创建对象
FileOutputStream fos = new FileOutputStream("E:\\aaa\\abc.txt");//如果它存在,就清空内容
2.写入数据:
将97对应的Ascll码值输出到文件夹里,一次只能写一个,下次写的数据会将上次写的数据覆盖
fos.write(97);
3.批量插入
byte[] b = {97, 98, 99, 100, 101, 102, 103, 104, 105};
fos.write(b);//将整个数组的内容都插入到文件夹中
fos.write(b, 1, 3);//将数组b中从起始索引1一直往后个数为3插入到文件夹中
4.释放资源:
也就是说让idea停止占用这个文件夹。
fos.close();
1.1.2:写字符串与换行符
1.创建对象
新写入元素会清空文件夹,此时你加了true,表示可以续写,默认开关是flase,
FileOutputStream fos = new FileOutputStream("E:\\aaa\\abc.txt",true);
2.写出数据
写字符串一般需要用byte字节数组
String str="asdfgjhkl";
byte[] bytes1 = str.getBytes();
fos.write(bytes1);
String str2="666";
byte[] bytes3 = str2.getBytes();
fos.write(bytes3);
3.换行
String str1="\r\n";
byte[] bytes2 = str1.getBytes();
fos.write(bytes2);
4.释放资源
fos.close();
1.2:读数据(FileInputStream)
1.创建对象
FileInputStream fis=new FileInputStream("E:\\aaa\\abc.txt");
读的函数,每次只读一个字符串,读到最后没有数据了,那就返回-1。
如果最后一个数据是-1,则先打印“-”再打印1(转了Char)
2.开始读取
int read1 = fis.read();
System.out.println((char)read1);
int read2 = fis.read();
System.out.println((char)read2);
int read3 = fis.read();
System.out.println((char)read3);
3.循环遍历
3.1:正确遍历方法
int b;
while((b=fis.read())!=-1){
System.out.println(b);
}
3.2:错误遍历方法
while(fis.read()!=-1){
//read函数的细节:他是获取到每一个元素并且将指针指向下一个元素
System.out.println(fis.read());
//到这里输出的时候其实就已经指向的时第二个元素了
4.释放资源:
fis.close();
1.3:文件操作:
1.3.1:拷贝文件(普通版):
//文件拷贝
FileInputStream fis=new FileInputStream("E:\\反诈视频2.mp4");
FileOutputStream fos=new FileOutputStream("MyIo\\copy.mp4");
long start= System.currentTimeMillis();
int b;
while((b=fis.read())!=-1){
fos.write(b);
}
long end=System.currentTimeMillis();
System.out.println(end-start);
//释放资源
//一般来说:先创建的对象先释放
fos.close();
fis.close();
1.3.2:编码与解码:
//1.编码
String str = "ai你哟";
byte[] b = str.getBytes();//变成字节数组 默认情况下为utf-8编码规则
System.out.println(Arrays.toString(b));//转换成字符串,变成Ascll码值
byte[]b2=str.getBytes("GBK");//编码规则为GBK
System.out.println(Arrays.toString(b2));
//2.解码
String str2=new String(b);//默认解码的方式为utf-8
System.out.println(str2);
String str3=new String(b2,"GBK");//用GBK的编码方式
System.out.println(str3);
补充:
编码表
(1)什么是字符集
是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBXXX字符集、Unicode字符集等。
(2)常见的字符集
ASCII字符集ASCII:是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号) 。
基本的ASCII字符集,使用7位表示一个字符,共128字符。ASCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
GBXXX字符集
GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等。
Unicode字符集
UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用 中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码。
(3)编码规则
128个US-ASCII字符,只需一个字节编码
拉丁文等字符,需要二个字节编码
大部分常用字(含中文),使用三个字节编码
其他极少使用的Unicode辅助字符,使用四字节编
1.3.3:文件拷贝(会员版):
FileInputStream fis = new FileInputStream("E:\\反诈视频2.mp4");
FileOutputStream fos = new FileOutputStream("MyIo\\copy1.mp4");
long start= System.currentTimeMillis();
int b;
byte[] buf = new byte[1024*1024*5];//5Mb/s
while((b=fis.read(buf))!=-1){
fos.write(buf,0,b);
}
long end=System.currentTimeMillis();
System.out.println(end-start);//6ms就已经搞完了,没有加速要11秒,快了2000多倍
//释放资源
//一般来说:先创建的对象先释放
fos.close();
fis.close();
1.3.4:文件压缩:
//压缩文件
//本质就是将文件中的Entry对象变成文件
//创建file对象表示要压缩的文件
File file = new File("E:\\aaa\\abcd.txt");
//创建file对象表示压缩包的位置
File dest = new File("E:\\");
toZip(file, dest);
}
public static void toZip(File src, File dest) throws IOException {
//1.创建压缩流关联压缩包
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest, "a.zip")));
//2.创建ZipEntry对象,用来表示压缩包里的文件和文件夹
ZipEntry entry = new ZipEntry("a.txt");
//参数:其实是压缩包里的路径
//3.把ZipEntry对象放到压缩包里
zos.putNextEntry(entry);
//4.将file文件的数据写到压缩包里
FileInputStream fis = new FileInputStream(src);
int b;
while ((b = fis.read()) != -1) {
zos.write(b);
}
zos.closeEntry();
zos.close();
fis.close();
}
1.3.5:文件解压:
//文件解压
//1.创建一个File表示要解压的压缩包
File f=new File("E:\\ccc.zip");
//创建一个新的File表示解压的目的地
File dest=new File("E:\\");//表示将其解压到D盘的根目录下面
unZip(f,dest);
}
//创建一个方法来实现
public static void unZip(File f,File dest) throws IOException {
//文件解压的本质就是将文件中的entry对象拷贝到目的文件中
//创建一个解压缩流来读取压缩包中的数据
ZipInputStream zip=new ZipInputStream(new FileInputStream(f));
//先获取数据中的Entry对象
ZipEntry entry = zip.getNextEntry();
while(entry!=null){//如果是获取不到对象了,那就返回null
if(entry.isDirectory()){//如果是文件夹,那就要创建新的文件夹
File file=new File(dest,entry.getName());//父级路径dest,子级路径entry.getName()
file.mkdirs();//创建一个文件夹,boolean类型的,创建成功,返回true,创建失败:返回flase
}else{//如果是文件,就直接拷贝
FileOutputStream fos=new FileOutputStream(new File(dest,entry.getName()));
int b;
while((b=zip.read())!=-1){
fos.write(b);
}
fos.close();
zip.closeEntry();
}
}
zip.close();
}
1.3.6:字节打印流:
//字节打印流
PrintStream ps = new PrintStream(new FileOutputStream("MyIo\\fun.txt"));
ps.println("Hello World");//写出,自动刷新,自动换行
ps.print("Hello World");
ps.println();
ps.printf("%s爱上了%s","阿珍","阿强");
//System.out.println();
//输出语句的底层就是一个打印流
PrintStream p= System.out;
p.println("hello world");
p.print("hello world");
p.println("你好你好");
//第一个打印流,释放资源
ps.close();
1.3.7:字符打印流:
//字符打印流
PrintWriter pw = new PrintWriter(new FileWriter("MyIo\\fun.txt"));
pw.println("Hello World");
pw.print("Hello World");
pw.println();
pw.printf("%s爱上了%s", "阿珍", "阿强");
pw.close();
二、字节缓冲流:
字节缓冲流是在 Java 的输入输出(IO)体系中,用于提高字节流读写效率的一种流。它内部包含了一个缓冲区,通过将数据先读入缓冲区或者先写入缓冲区,减少了对底层物理设备(如硬盘、网络等)的直接读写次数,从而提高了数据传输的效率。
众所周知:没有什么是加一层中间层不能解决的
2.1:写数据:
将对象集合写入文件
Student s1=new Student("张三",23,"南京");
Student s2=new Student("李四",24,"红京");
Student s3=new Student("王五",23,"天京");
Student s4=new Student("赵六",23,"北京");
ObjectOutputStream oos = new ObjectOutputStream(new
FileOutputStream("C:\\Users\\IdeaProjects\\string\\MyIo\\abcd.txt"));
ArrayList<Student> list=new ArrayList<Student>();
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
oos.writeObject(list);
oos.close();
2.2:读数据
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\IdeaProjects\\string\\MyIo\\abcd.txt"));
ArrayList<Student> list1 = (ArrayList<Student>) ois.readObject();
for (Student student : list1) {
System.out.println(student);
}
ois.close();
2.3:字节缓冲流提高提高效率的原理:
1.我们知道字节流是没有缓冲区的,而字节缓冲流就加了缓冲区
内存
数据源-------缓冲区1 缓冲区2----------目的地内存中间就加了俩个缓冲流,如果没加byte数组进行传输,那就内存里从缓冲区1往缓冲区2里面一个一个搬数据
如果加了byte数组,那就按照byte数组的长度进行搬运数据
注意:其实内存里搬运数据是非常快的(因为是硬件实现的)
所以提高速度的真实原因是缓冲区的建立,减少了内存与文件之间的交互
三、 字符流:
3.1:读数据:
FileReader fr=new FileReader("E:\\bbb\\a.txt");
read函数是一个字节一个字节的读,当遇到中文时,就会读取多个字节(utf-8为3个,GBK为2个)
底层会把读到的二进制数据转换成十进制
也就是文件里的中文被系统utf-8编码成二进制数据,然后read函数会将其转换成十进制
如果想再读取到中文,用(char)强转
int ch;
while((ch=fr.read())!=-1){
System.out.print((char)ch);
}
释放资源
fr.close();
FileReader fr = new FileReader("E:\\bbb\\a.txt");
char[] ch=new char[2];
int len;
while((len=fr.read(ch))!=-1){//read函数与没有参数的read函数不同,这个有参数的read函数=没有参数的read+强转
System.out.println(new String(ch,0,len));
}
3.1.1:JDK11前后区别:
JDk11之前是这么个事:
InputStreamReader isr = new InputStreamReader
(new FileInputStream("C:\\Users\\IdeaProjects\\string\\MyIo\\abcd.txt"),"UTF-8");
int b;
while ((b=isr.read())!=-1){
System.out.print((char)b);
}
isr.close();
JDK11之后变成这么个事了:
FileReader fr=new FileReader("C:\\Users\\IdeaProjects\\string\\MyIo\\abcd.txt", Charset.forName("UTF-8"));
int b;
while((b=fr.read())!=-1){
System.out.print((char)b);
}
fr.close();
3.2:写数据:
3.2.1:单个数据写入文件
FileWriter fw=new FileWriter("E:\\bbb\\a.txt",true);
//写出一个字符
fw.write(97);
//写出一个字符串
fw.write("我爱中国");
//写出字符串的一部分
fw.write("我爱中国",1,3);//从一索引到三索引
//写出一个字符数组
char []c={'a','b','c'};
fw.write(c);
//写出字符数组的一部分
fw.write(c,1,2);
fw.close();
3.2.2: 文件数据传输
//底层:缓冲区
//注意:只有字符流才有缓冲区,字节流是没有缓冲区的
FileReader fr = new FileReader("E:\\bbb\\a.txt");
fr.read();//第一次调用这个方法,内存里就会开辟一个缓冲区(容量为8192字节),会将这个缓冲区尽可能的装满
FileWriter fr1 = new FileWriter("E:\\bbb\\a.txt");//注意此时文件里的数据会被清空
int ch;
while ((ch = fr.read()) != -1) {
System.out.print((char) ch);
}//此时,虽然文件里的数据被清空了,但是在第一个read方法时他就将数据都存在了缓冲区里
//所以此时我们是从缓冲区里拿数据,所以此时依然可以获取到数据
fr1.close();
fr.close();
3.2.3:文件夹的拷贝
//文件夹的拷贝
//1.创建对象来确定数据源
File src=new File("E:\\bbb");
//2.创建对象来确定目的地
File dest=new File("E:\\ccc");
copydir(src,dest);
}
private static void copydir(File src, File dest) throws IOException {
//进入数据源
File[] files=src.listFiles();
if (files!=null) {
//遍历数组
for (File file : files) {
if(file.isFile()) {
//直接拷贝,拷贝使用字节流
FileInputStream fis = new FileInputStream(src); //父级路径,//子级路径,二者相拼接
FileOutputStream fos = new FileOutputStream(new File(dest, file.getName()));
byte[] b = new byte[1024];
int len;
while((len=fis.read(b))!=-1){
fos.write(b,0,len);
}
}else{
copydir(file, new File(dest, file.getName()));
}
}
}
}
4.使用工具类的一些快捷方法来实现文件的操作
4.1:拷贝文件
File src=new File("MyIo\\fun.txt");
File dest=new File("MyIo\\copyfun.txt");
FileUtils.copyFile(src,dest);
4.2:拷贝文件夹
File src=new File("E:\\ccc");
File dest=new File("E:\\ddd");
FileUtils.copyDirectory(src, dest);//(将src中的文件拷贝到dest当中去)
FileUtils.copyFileToDirectory(src, dest);//(将src本身一起打包复制给dest)
4.3:删除文件夹
File src = new File("E:\\ccc");
FileUtils.deleteDirectory(src);
4.4:清空文件夹
FileUtils.cleanDirectory(src);
4.5:读取文件(注意是文件)中的数据变成字符串
File src = new File("E:\\ddd\\abc.txt");
String s = FileUtils.readFileToString(src);
System.out.println(s);
四、字符缓冲流
BufferedWriter
(1)介绍:
将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途。
BufferedReader
从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途。
(2)构造方法
| BufferedWriter(Writer out) | 创建字符缓冲输出流对象 |
| BufferedReader(Reader in) | 创建字符缓冲输入流对象 |
(3)代码演示
public class BufferedStreamDemo01 {
public static void main(String[] args) throws IOException {
//BufferedWriter(Writer out)
BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\bw.txt"));
bw.write("hello\r\n");
bw.write("world\r\n");
bw.close();
//BufferedReader(Reader in)
BufferedReader br = new BufferedReader(new FileReader("myCharStream\\bw.txt"));
//一次读取一个字符数据
// int ch;
// while ((ch=br.read())!=-1) {
// System.out.print((char)ch);
// }
//一次读取一个字符数组数据
char[] chs = new char[1024];
int len;
while ((len=br.read(chs))!=-1) {
System.out.print(new String(chs,0,len));
}
br.close();
}
}
(4)字符缓冲流特有功能
void newLine()写一行行分隔符,行分隔符字符串由系统属性定义
String readLine()读一行文字。 结果包含行的内容的字符串,不包括任何行终止字符如果流的结尾已经到达,则为null
结尾:
至此,我们已经对 Java IO 流进行了全面的探讨,从基本概念到各种类型的流及其高级功能,相信你已经对如何使用 Java 中的 IO 流有了深入的了解。掌握这些知识,你将能够在自己的 Java 开发中熟练地处理各种数据输入和输出任务,为你的程序带来更强的交互性和数据处理能力。然而,Java IO 流的世界还在不断发展,新的特性和改进也会随着 Java 版本的更新而不断涌现,希望你能够将这里所学的基础作为起点,持续探索和学习,为自己的编程之旅打开更广阔的天地。
请记住,在使用 IO 流时,始终要注意资源的管理,确保及时关闭打开的流,以避免资源泄漏。同时,根据不同的数据类型和处理需求,合理选择使用字节流还是字符流,以及适当的缓冲和过滤机制,将有助于你编写出更高效、更稳定的代码。不断地实践和尝试,会让你在 IO 流的使用上越来越得心应手,为你的 Java 开发工作带来更多的便利和创新。
原文地址:https://blog.csdn.net/2301_78506180/article/details/145173737
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!