当前位置: 首页 > news >正文

java之IO篇——File、字节流、字符流

前言

IO流是用于读写文件中的数据,要读写文件之前可以创建文件获取文件对象再创建IO流,正文会先介绍File类,通过File类的构造方法获取文件的对象,创建文件或目录以及File类的一些方法获取文件对象的属性。后面还介绍了相关的IO流体系,字节流和字符流的区别用法。

目录

前言

一、File

1.常用的成员方法

(1) 判断、获取

(2)创建、删除

(3)获取并遍历 

2. 实操

(1)遍历C盘下的以.avi结尾的文件

(2)删除一个多级文件夹(里面的有些文件有内容) 

(3)统计各种文件的数量 

二、IO流分类

三、IO体系

1.字节流

 2.字符流

四、字节流

1.字节输出流

(1)用法

(2)进阶用法(换行和续写)

 2.字节输入流

(1)用法

3.拷贝

五、try-with-resources

六、字符集(ASCLL、GBK、Unicode)

七、读取出现乱码

1.原因

2.解决方法

3.编码和解码

八、字符流

1.特点

2.使用场景

3.字符输出流

(1)用法

(2)底层原理

4.字符输入流

(1)用法

(2)底层原理

 九、字节流和字符流实战

1.拷贝文件夹

2.加密解密

3.将文件排序


一、File

1.常用的成员方法

(1) 判断、获取

注意: 1.length返回文件的大小(字节数量)

                细节1:这个方法只能获取文件的大小,单位是字节

                如果单位我们要是M,G,可以不断的除以1024

                细节2:这个方法无法获取文件夹的大小

                如果我们要获取一个文件夹的大小,需要把这个文件夹里面所有的文件大小都累加在一起。

           2.getName获取名字

                细节1:file是文件会返回文件的文件名和扩展名(如.txt  .cpp)

                细节2:file是文件夹就返回文件夹的名字。

(2)创建、删除

注意:1.createNewFile创建一个新的空的文件

                细节1:如果当前路径表示的文件是不存在的,则创建成功,方法返回true

                             如果当前路径表示的文件是存在的,则创建失败,方法返回false

                细节2:如果父级路径是不存在的,那么方法会有异常IOException

                细节3:createNewFile方法创建的一定是文件,如果路径中不包含后缀名,则创建一个没有后缀的文件

           2.mkdir创建一个文件夹(目录)

                细节1:windows当中路径是唯一的,如果当前路径已经存在,则创建失败,返回false

                细节2:mkdir方法只能创建单级文件夹,无法创建多级文件夹。

          3. mkdirs创建多级文件夹

                细节:既可以创建单级的,又可以创建多级的文件夹

          4.delete删除文件、空文件夹

                细节:如果删除的是文件,则直接删除,不走回收站。

                          如果删除的是空文件夹,则直接删除,不走回收站

                          如果删除的是有内容的文件夹,则删除失败  

(3)获取并遍历 

注意:细节: 

  

//1.创建File对象
File f = new File("D:\\aaa");
//2.listFiles方法
//作用:获取aaa文件夹里面的所有内容,把所有的内容放到数组中返回
File[] files = f.listFiles();
for (File file:files) {//file依次表示aaa文件夹里面的每一个文件或者文件夹System.out.println(file);
}

2. 实操

(1)遍历C盘下的以.avi结尾的文件

递归,一定要先用if判断文件数组是否为空,否则会抛出空指针异常

(2)删除一个多级文件夹(里面的有些文件有内容) 

(3)统计各种文件的数量 

 /** 作用:*       统计一个文件夹中每种文件的个数* 参数:*       要统计的那个文件夹* 返回值:*       用来统计map集合*       键:后缀名 值:次数**       a.txt*       a.a.txt*       aaa(不需要统计的)*** */public static HashMap<String,Integer> getCount(File src){//1.定义集合用来统计HashMap<String,Integer> hm = new HashMap<>();//2.进入src文件夹File[] files = src.listFiles();//3.遍历数组for (File file : files) {//4.判断,如果是文件,统计if(file.isFile()){//a.txtString name = file.getName();String[] arr = name.split("\\.");if(arr.length >= 2){String endName = arr[arr.length - 1];if(hm.containsKey(endName)){//存在int count = hm.get(endName);count++;hm.put(endName,count);}else{//不存在hm.put(endName,1);}}}else{//5.判断,如果是文件夹,递归//sonMap里面是子文件中每一种文件的个数HashMap<String, Integer> sonMap = getCount(file);//hm:  txt=1  jpg=2  doc=3//sonMap: txt=3 jpg=1//遍历sonMap把里面的值累加到hm当中Set<Map.Entry<String, Integer>> entries = sonMap.entrySet();for (Map.Entry<String, Integer> entry : entries) {String key = entry.getKey();int value = entry.getValue();if(hm.containsKey(key)){//存在int count = hm.get(key);count = count + value;hm.put(key,count);}else{//不存在hm.put(key,value);}}}}return hm;}
}

二、IO流分类

纯文本文件,就是Windows自带的记事本打开能读懂的。比如(.txt  .md)

三、IO体系

1.字节流

 文件操作是程序通过IO流来读写文件。

 输入的意思是将文件的数据读进来,进到程序来,加上操作的对象是本地文件,所以实现类FileInputStream叫做操作本地文件的字节输入流。

相反的,输出的意思就是,文件的操作者——程序,将修改的数据写到文件里面,即输出到文件去。加上操作的对象是本地文件,所以实现类FileOutputStream叫做操作本地文件的字节输出流。

字节流不仅有文件流 ,还有缓冲流BufferedInputStream、BufferedOutputStream,数据流DataInputStream、DataOutputStream,对象流ObjectInputStream、ObjectOutputStream,打印流PrintStream等等还有很多。

 2.字符流

 字符流的输入和输出和字节流的输入输出一个意思,不同的就是字符流的底层是字节流+字符集。字节流是一个字节一个字节读取的,而字符流是普通字符就一个字节,遇到中文就按字符集的规则多个字节读。

字符流不仅有文件字符流,还有缓冲字符流等等

 

四、字节流

以文件流FileInputStream、FileOutputStream为例

1.字节输出流

(1)用法

1.创建字节输出流对象

2.写数据

3.释放资源

详解:

1.创建字节流对象(2+2)

下面是两个构造方法 传递一个绝对/相对路径的字符串    或者   传递一个File对象

//通过文件的路径创建文件输出流
FileOutputStream fos = new FileOutputStream("files\\test1.txt");
//通过文件对象创建文件输出流
File file = new File("files\\test1.txt");
FileOutputStream fos1 = new FileOutputStream(file);

 细节:参数是字符串表示的路径或者是File对象都是可以的

            如果文件不存在构造方法会创建一个新的文件,但是要保证父级路径是存在的。

            如果文件存在造方法会清空文件

如果我们不想要创建字节流的时候把原本文件内容清空,我们必须使用另外的两个构造器,

在原来一个参数的构造器的基础上,加上第二个参数,true表示续写。

2.写数据(write方法3种参数)

细节:write方法的参数是整数,但是实际上写到本地文件中的是整数在ASCII上对应的字符

一个一个查ASCLL这样子写下来会不会太麻烦了?

还有更简便的方法,将想要的数据传入一个String字符串,再通过String类的getBytes()方法将字符串转换为字节数组,最后将字节数组传递给write方法。

3.释放资源

每次使用完流之后都要释放资源

细节:如果流不关闭,并且当前使用流的程序没有停止,那么这个文件就不能被删除。

(2)进阶用法(换行和续写)

1.换行写:

再次写出一个换行符就可以了(每一个操作系统的换行符都不一样)

windows:  \r\n

Linux:       \n

Mac:         \r

写入文件的内容为:

kankelaiyezuishuai

666

2.续写

续写就是创建输出流的时候选用有第二个参数append的构造器。如下

 

 2.字节输入流

(1)用法

1.创建字节输入流对象

2.读数据

3.释放资源

 1.创建字节输入流对象

通过输入流的构造方法,创建输入流对象,一样都是传入一个绝对/相对路径的字符串或File对象

 细节:如果文件不存在,就直接报错。

Java为什么会这么设计呢?

看前面的输出流:不存在,就创建,把数据写到文件当中

而为什么输入流不存在是报错呢?

因为创建出来的文件是没有数据的,没有任何意义。所以Java就没有设计这种无意义的逻辑,文件不存在直接报错。

2.读数据(read方法3个)

int read()读取一个字节,读完后指针后移一位

int read(byte[] b)从该输入流读取最多b.length字节的数据到字节数组。以整数形式返回实际读取的字节数。

细节:无参的read方法一次读一个字节,读出来的是数据在ASCII上对应的数字

           读到文件末尾了,read方法返回-1。

          有参的read方法一次读一个字节数组的数据,读到的数据是以覆盖的形式覆盖原本的字节数组,比如说一个文件内容为abcde以长度为2的字节数组读取

FileInputStream fis = new FileInputStream("files\\test1.txt");
byte[] buffer = new byte[2];
int len;
//字节个数是2 读到的数据ab覆盖空数组
len = fis.read(buffer);//2
System.out.println("读取了" + len + "个字节,数据为"+ new String(buffer,0,2));//ab
//字节个数是2 读到的数据cd覆盖掉原本的ab
len = fis.read(buffer);//2
System.out.println("读取了" + len + "个字节,数据为"+ new String(buffer,0,2));//cd
//字节个数是1 读取的数据e只覆盖掉原本的cd的第一个字节
len = fis.read(buffer);//1
System.out.println("读取了" + len + "个字节,数据为"+ new String(buffer,0,2));//ed
//字节个数是-1 无覆盖还是ed
len = fis.read(buffer);//-1
System.out.println("读取了" + len + "个字节,数据为"+ new String(buffer,0,2));//ed

优化后代码(实际上用的)

3.释放资源

每次使用完流必须要释放资源。

注意:用字节流读取文件中的中文,会输出乱码。原因后面第七有讲

3.拷贝

顾名思义就是将一个文件的内容复制到另外一个文件。

拷贝的核心思想就是边读边写

一个字节从文件读到程序,程序写到文件

上面这种拷贝仅适用于拷贝小文件,内存比较小的。

弊端:一次读写一个字节,太慢了,大文件拷贝不适用

优化后:一个5M的字节数组读写拷贝

五、try-with-resources

注意:try后面括号里面的流类型必须实现AutoCloseable接口,它爹实现也行。

六、字符集(ASCLL、GBK、Unicode)

ASCLL:一个字节,0~127一共128个字符

GBK:两个字节,第一个字节的第一个二进制数一定是1,所以第一个字节一定是负数,第二个字节可正可负

Unicode:不同编码规则不同字节数,以UTF-8为例 是1~4个字节(一个英文占一个字节,一个中文占3个字节)

七、读取出现乱码

1.原因

1.读取数据时未读完整个汉字

2.编码和解码的方式不统一 

2.解决方法

1.不要使用字节流读取文本文件

2.编码和解码的时候使用同一个码表,即同一个编码方式

注意:拷贝的时候,出现乱码跟使用字节流无关,使用字节流出现乱码的情况是读取单个数据的时候,拷贝是整个文件的所有字节。如果拷贝出现乱码原因就只有编码和解码的方式不统一 。

3.编码和解码

idea默认编码方式是utf-8  中文占3个字节

Eclipse则是GBK  中文占2个字节

示例

String str = "ai你余";
//编码
byte[] bytes = str.getBytes();
System.out.println(Arrays.toString(bytes));
//以GBK解码
System.out.println(new String(bytes,"GBK"));

运行结果

 

编码和解码的编码格式不一样,导致乱码。

八、字符流

 

1.特点

字符输入流:一次读一个字节,遇到中文读多个字节 (具体读几个与字符集有关)

字符输出流:底层会把数据按照指定的编码方式进行编码,变成字节再写到文件中

2.使用场景

对于纯文本文件进行读写

3.字符输出流

(1)用法

1.创建字符输出流对象

2.写数据

3.释放资源

详解: 

1.创建字符输出流对象

前两个构造方法打开一个文件的输出流就会清空文件,如果文件不存在就创建文件,后面两个第二个参数传入true表示不会清空文件 

 2.写数据

 细节:如果write方法的参数是整数,但是实际上写到本地文件中的是整数在字符集上对应的字符

虽然字节流也有一样的int参数的write方法,但是字节流的只能传入0~127的范围,不然写到文件中的是乱码。而字符流写入文件会按照字符集来编码,超过127的编码成中文。

(2)底层原理

字符流写数据的时候是先将数据编码成字节写到缓冲区,缓冲区达到上面三种情况,就会写到文件里面。 刷新缓冲区flush和关闭流close是有区别的。

4.字符输入流

(1)用法

1.创建字符输入流对象

2.读取数据

3.释放资源

详解:

1.创建字符输入流对象

细节:如果文件不存在,就直接报错

 2.读取数据

使用无参的read方法是返回的是一个或多个(中文)的字节码的解码(已解码转十进制),要得到文件原本的内容就必须强转 (char)返回值

使用有参的read方法与字节流不同的是读到的数据用字符数组接收。

细节: 按字节进行读取,遇到中文,一次读多个字节,读取后解码,返回一个整数

           读到文件末尾了,read方法返回-1。

 3.释放资源

(2)底层原理

细节:如果缓冲区的8192个字节读完,缓冲区就会刷新,重新向文件读取新的字节数据,如果新的字节数据长度没有达到8192,新的字节数据只会覆盖缓冲数组前面的部分,后面部分保持原来的数据。

 九、字节流和字符流实战

应用场景

字节流  拷贝任意类型的文件

字符流  拷贝纯文本文件

1.拷贝文件夹

    public static void main(String[] args) throws IOException {File src = new File("files");File dest = new File("copy");copy(src,dest);}private static void copy(File src,File dest) throws IOException {if (src.exists()){return;}else if (src.isDirectory()){File[] files = src.listFiles();if (files != null) {for (File file : files) {String name = file.getName();String destPath = dest.getAbsolutePath();String path = destPath+ File.separator+name;File file1 = new File(path);if (file.isDirectory()){file1.mkdir();copy(file,file1);}else {try (FileWriter fileWriter = new FileWriter(file1,true);FileReader fileReader = new FileReader(file)) {int len;while ((len = fileReader.read()) != -1) {fileWriter.write(len);fileWriter.flush();}}}}}}}

2.加密解密

加密就是,将一个文件写到另外一个文件的时候,对流中的每一个字节做处理,比如下面的例子就是异或一个2

解密就是,将一个无法解读的文件,写到另外一个文件,对每一个字节做解密处理,下面的例子加密时是异或一个2,那么解密就是继续异或一个2异或回来

3.将文件排序

文件里的内容是[1-9-2-6-5-4-3]

重新排序成[1-2-3-4-5-6-9]

        //1.获取文件中的数据FileReader fr = new FileReader("files\\test1.txt");StringBuilder sb = new StringBuilder();int len;while ((len = fr.read()) != -1) {sb.append((char) len);}//2.排序String[] strings = sb.toString().substring(1, sb.length() - 1).split("-");Integer[] arr = Arrays.stream(strings).map(Integer::parseInt).sorted().toArray(Integer[]::new);//3.写出FileWriter fw = new FileWriter("files\\test1.txt");fw.write(Arrays.toString(arr).replace(", ", "-"));fr.close();fw.close();

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【IO】使用有名管道实现,一个进程用于给另一个进程发消息,另一个进程收到消息后,展示到终端上,并且将消息保存到文件上一份
  • 新书速览|AI创意商业广告设计:Adobe Firefly + Photoshop
  • 现代前端架构介绍(第一部分):App是如何由不同的构建块构成的
  • 数据中台建设之数据汇聚与数据交换
  • Apache Pig: 高级数据处理平台
  • 【开源】嵌入式Linux(IMX6U)应用层综合项目(1)--云平台调试APP
  • 网络流算法:最大流问题
  • SparkSQL---编程模型的操作,数据加载与落地及自定义函数的使用
  • 最新全国各省市水系矢量数据(2024年更新)
  • 【教学类-73-02】20240805广口瓶(宽口瓶)02
  • 类和对象——日期类实现
  • 从一到无穷大 #32 TimeCloth,云上的快速 Point-in-Time Recovery
  • [Meachines] [Easy] shocker CGI-BIN Shell Shock + Perl权限提升
  • python rsa如何安装
  • live2d C++ sdk 分析
  • [LeetCode] Wiggle Sort
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • [译] React v16.8: 含有Hooks的版本
  • 【技术性】Search知识
  • Angular数据绑定机制
  • C++类的相互关联
  • CSS进阶篇--用CSS开启硬件加速来提高网站性能
  • js学习笔记
  • LeetCode29.两数相除 JavaScript
  • Mysql5.6主从复制
  • Python学习之路13-记分
  • Vue全家桶实现一个Web App
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 阿里云前端周刊 - 第 26 期
  • 服务器从安装到部署全过程(二)
  • 基于组件的设计工作流与界面抽象
  • 技术胖1-4季视频复习— (看视频笔记)
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 实习面试笔记
  • 收藏好这篇,别再只说“数据劫持”了
  • 白色的风信子
  • 1.Ext JS 建立web开发工程
  • ionic入门之数据绑定显示-1
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • # linux 中使用 visudo 命令,怎么保存退出?
  • %@ page import=%的用法
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (30)数组元素和与数字和的绝对差
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (vue)el-cascader级联选择器按勾选的顺序传值,摆脱层级约束
  • (办公)springboot配置aop处理请求.
  • (动手学习深度学习)第13章 计算机视觉---图像增广与微调
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (分布式缓存)Redis哨兵
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • .NET Core IdentityServer4实战-开篇介绍与规划
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .net core 控制台应用程序读取配置文件app.config
  • .NET Framework 3.5中序列化成JSON数据及JSON数据的反序列化,以及jQuery的调用JSON