Java基础文件操作(IO流)

网友投稿 680 2022-05-28

特意写一章关于IO流的知识,不为别的,是因为IO流实在太重要了

文件

File 就是文件对象,我们电脑上的文件和文件夹都可以用这个File实例化

public class Test{     public static void main(String[] args){         // 获取绝对路径D盘的hello文件夹         File f1 = new File("D:/hello");         // 获取相对路径的hello.txt文件         File f2 = new File("hello.txt");         // 获取D盘的hello文件夹下hello.txt文件的实例         File f3 = new File(f1,"hello.txt");                  // 输出三个文件或者文件夹的绝对路径         System.out.println(f1.getAbsolutePath());         System.out.println(f2.getAbsolutePath());         System.out.println(f3.getAbsolutePath());     }}123456789101112131415

上面代码注释讲的已经非常的详细了,用三种方式创建一个文件对象,怎么获取文件的绝对路径

假设我们已经实例化了一个File对象f

判断是否存在 f.exists()

判断是否是文件夹 f.isDirectory()

判断是否是文件 f.isFile()

获取文件的长度 f.length()

文件最后修改的时间 f.lastModified()

设置文件最后修改时间 f.setLastModified(0) 这里的0代表的是时间戳 也就是1970.1.1 08:00:00

文件重命名 f.renameTo(“newName”)

以字符串数组的形式,返回当前文件夹下面的所有文件 f.list()

以文件数组的形式,返回当前文件夹下面的所有文件 f.listFiles()

以字符串形式返回所在文件夹 f.getParent()

以字符串形式返回获取所在文件夹 f.getParentFile()

创建一个文件夹 f.mkdir() 如果说f所在的父文件夹不存在就会抛出异常

创建一个文件夹 f.mkdirs() 如果说f所在的父文件夹不存在就会自动给你创建一个父文件夹

删除文件 f.delete()

JVM结束的时候删除文件 f.deleteOnExit()

public class Test{     public static void main(StringP[] args){         File f = new File("C:/WINDOWS");         File[] files;         int k=0;         long max = 0;         if(f.exists){             // 把文件夹下面的所有文件都取出来             files = f.listFiles();             // 遍历所有的文件取出体积最大的文件             for(int i=0;imax){                     //如果比最大的文件还大就把他的下标记下来                     k = i;                     max = files[i].length();                 }             }         }else{             System.out.println("文件夹不存在");         }                  // 输出找到的最大的文件路径和它体积         System.out.println("最大文件路径: "+files[k]);         System.out.println("最大文件体积: "+files[k].length()+" 字节");     }}1234567891011121314151617181920212223242526

编码

编码是信息从一种形式或格式转换为另一种形式的过程

常见的编码方式有如下几种:

ISO-8859-1 ASCII 数字和西欧字母

GBK GB2312 BIG5 中文

UNICODE (统一码,万国码)

看样子,我们的中文就是属于这个GBK这种编码了,也就是说中文只能用GBK编码来存储嘛?

这个肯定是错的,UNICODE称为万国码,也就是全世界任何国家的字符都是可以储存的,只不过,他占用的空间是最大的,比入英文字母只需要1字节的空间,汉字需要3字节的空间,但是Unicode它不管你是英文字母还是汉字,都统一给你4个字节,这样的话是比较浪费空间的,所以就诞生了UTF-8这种基于Unicode减肥版本的编码方式。

UTF-8它可以对英文或者数字使用一个字节,对汉字使用三个字节,这样的话就避免了空间的浪费。

Java源代码中的汉字在执行之后,都会变成JVM中的字符,而这些中文字符采用的编码方式,都是Unicode

什么流?流就是一系列的数据。

当不同的介质之间有数据交互的时候,Java就是使用流来实现

比如读取文件的数据到程序中,站在程序的角度来看,就叫做输入流。

如何创建文件输入流,看以下代码:

public class Test{     public static void main(String[] args){         try{             File f = new File("D:/hello.txt");             // 通过这个文件输入流可以将硬盘上文件中的数据读取到java程序内存中来             FileInputStream fis = new FileInputStream(f);         }catch(IOException e){             e.printStackTrace();         }     }}1234567891011

InputStream是字节输入流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。

FileInputStream是InputStream的子类,我们下面就用FileInputStream来实现读取文件的内容

public class Test{     public static void main(String[] args){         try{             // 准备一个文本文件,里面内容是AB             File f = new File("D:/test.txt");             // 创建文件输入流             FileInputStream fis = new FileInputStream(f);             // 创建一个字节数组,它的长度就是文件的长度             byte[] all = new byte[(int)f.length()];             // 以字节流的形式读取文件中的所有内容到字节数组             fis.read(all);             for(byte b : all){                 System.out.println(b);            }             fis.close();                      }catch(IOException e){             e.printStackTrace();         }     }}123456789101112131415161718192021

结果是65和66 也就是A和B对应的ASCII码

OutputStream 是字节输出流,更InputStream也是一样的,抽象类。

Java基础之文件操作(IO流)

所以我们用FileOutputStream为例往文件中写入数据

public class Test{     public static void main(String[] args){         try{             // 准备一个文本文件,里面内容是空的             File f = new File("D:/test.txt");             // 创建文件输出流             FileOutputStream fis = new FileOutputStream(f);             // 创建一个字节数组,里面写上A和B的ASCII码             byte[] data = {65,66};             // 以字节流的形式将data里的数据写入到输出流             fis.write(all);             fis.close();          }catch(IOException e){             e.printStackTrace();         }     }}1234567891011121314151617

我们打开对应的文件,发现数据就已经写在里面了,但是输出流跟输入流有一个区别,就是输出流的时候不一定要求文件存在,当文件不存在的时候,会自动给我们创建一个新的文件,而输入流则会抛出异常

字符流:就是在字节流的基础上,加上编码,形成的数据流

字符流分为字符输入流Reader 和 字符输出流 Writer

他们常用的子类就是FileReader 和 FileWriter

在之前我们使用了字节输入流读取文件中的内容,读取的AB打印出来是65和66

现在我们来看一下使用字符输入流读取文件是什么样的结果

public class Test {       public static void main(String[] args) {         // 准备文件hello.txt其中的内容是AB         File f = new File("d:/hello.txt");         // 创建基于文件的Reader         try (FileReader fr = new FileReader(f)) {             // 创建字符数组,其长度就是文件的长度             char[] all = new char[(int) f.length()];             // 以字符流的形式读取文件所有内容             fr.read(all);             for (char b : all) {                 // 打印出来是A B                 System.out.println(b);             }         } catch (IOException e) {             // TODO Auto-generated catch block             e.printStackTrace();         }       }}12345678910111213141516171819202122

字符输入流可以直接读取文件中的字符

我们可以直接将一串字符存储到文件中,代码如下:

public class Test{     public static void main(String[] args){         // 创建文件对象,文件内容是空的         File f = new File("D:/hello.txt");         // 要写入的字符串         String str = "hello";        char[] cs = str.toCharArray();         try(FileWrter fw = new FileWriter(f)){             fw.write(cs)         }catch(IOException e){             e.printStackTrace();         }     }}1234567891011121314

文件中的内容就会变称hello

上面我们学习了字节流和字符流,那么我们分别用两种流来从文件中读取汉字内容。

首先你得了解文本是以哪种编码方式进行保存的

使用字节流读取文本后,再使用对应的编码方式去识别这些文字

public class Test{     File f = new File("D:/hello.txt");     try(FileInputStream fis = new FileInputStream(f)){         byte[] all = new byte[(int) f.length()];         fis.read(all);         //将读到的字节进行编码输出         String str = new String(all,"GBK");         System.out.println(str);     }catch(IOException e){         e.printStackTrace();     }}123456789101112

FileReader得到的字符,肯定是已经把字节根据某种编码方式识别成的字符。

FIleReader的编码方式可以用Charset.defaultCharset()获取,如果是中文的操作系统那么就是GBK

假设现在我们的文件是用UTF-8编码方式保存的,那么我们该如何使用字符流读取文字呢?

答案就是使用InputStreamReader,这个是字节流到字符流的桥接器,它可以按照指定的字符集读取字节并将它们转换为字符。

public class TestStream {     public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {         File f = new File("D:/hello.txt");         System.out.println("默认编码方式:"+Charset.defaultCharset());         //FileReader得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了         //而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK         try (FileReader fr = new FileReader(f)) {             char[] cs = new char[(int) f.length()];             fr.read(cs);             System.out.printf("FileReader会使用默认的编码方式%s,识别出来的字符是:%n",Charset.defaultCharset());             System.out.println(new String(cs));         } catch (IOException e) {             // TODO Auto-generated catch block             e.printStackTrace();         }         //FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替         //并且使用new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8")); 这样的形式         try (InputStreamReader isr = new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"))) {             char[] cs = new char[(int) f.length()];             isr.read(cs);             System.out.printf("InputStreamReader 指定编码方式UTF-8,识别出来的字符是:%n");             System.out.println(new String(cs));         } catch (IOException e) {             // TODO Auto-generated catch block             e.printStackTrace();         }               }}1234567891011121314151617181920212223242526272829

为什么中字的前面有一个?,如果你是用记事本另存为UTF-8的字符集编码的话,那么在第一个字节有一个标识,叫做BOM,用来标识这个文件是使用UTF-8编码的

以介质是硬盘为例,字节流和字符流的弊端:

在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。

为了解决以上弊端,采用缓存流。

缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中读取。

就好比吃饭,不用缓存就是每吃一口都到锅里去铲。用缓存就是先把饭盛到碗里,碗里的吃完了,再到锅里去铲

缓存流在写入数据的时候,会先把数据写入到缓存区,直到缓存区达到一定的量,才把这些数据,一起写入到硬盘中去。按照这种操作模式,就不会像字节流,字符流那样每写一个字节都访问硬盘,从而减少了IO操作

BufferedReader可以一次性读取一行数据

public class Test{     public static void main(String[] args){         /**         准备一个文件,里面的内容是         hello         world         你好         */         File f = new File("d:/hello.txt");         // 缓存字符输入流必须在一个存在的流的基础上创建         try(         FileReader fr = new FileReader(f);         BufferedReader br = new BufferedReader(fr);             ){             while(true){                 // 一次读取一行                 String line = br.readLine();                 if(line == null){                     break;                 }                 System.out.println(line);             }catch(IOException e){                 e.printStackTrace();             }         }     }}123456789101112131415161718192021222324252627

PrintWrite,可以一次写出一行数据

public class TestStream {         public static void main(String[] args) {         // 向文件lol2.txt中写入三行语句         File f = new File("d:/hello.txt");                    try (                           PrintWriter pw = new PrintWriter(f);                       ) {             pw.println("hello");             pw.println("world");             pw.println("你好");         } catch (IOException e) {             // TODO Auto-generated catch block             e.printStackTrace();         }         }}12345678910111213141516171819

这里需要注意的是,缓存字符输入流的构造方法的参数是一个Reader,也就是一个字符流,而PrintWriter的构造参数可以是文件对象也可以是字节流或者字符流对象!

分别是BufferedInputStream 和 BufferedOutputStream

下面代码演示的是通过缓存字节输入流和输出流实现文件的复制

public class Test{     public static void main(String[] args){         File file = new File("E:/我的文档/临时文件/视屏文件.ts");         File file1 = new File("E:/我的文档/临时文件/视屏文件(副本).ts");         try (                 FileInputStream fis = new FileInputStream(f);                 FileOutputStream fos = new FileOutputStream(f1);                 BufferedInputStream bis = new BufferedInputStream(fis);                 BufferedOutputStream bos = new BufferedOutputStream(fos);         ){             byte[] bytes = new byte[1024];             int len;             while(true){                 len = bis.read(bytes);                 if(len == -1){                     break;                 }                 bos.write(bytes,0,len);             }         }catch (IOException e){             e.printStackTrace();         }     }     }}

Java

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:企业微信+泛微:助力企业全方位开展营销活动,助力业绩增长
下一篇:JVM(5)——类加载机制
相关文章