File类 实例创建
此时并不能在硬盘中创建文件
ps: Windows: \\
; Unix: /
创建一个具体文件File类实例:File(String filePath)
1 2 File file1 = new File("hello.txt" ); File file2 = new File("D:\\JavaLearning\\JavaSenior\\day08\\hello.txt" );
创建一个具体文件夹File类实例:File(String parentPath, String childPath)
或File(File parentFile, String childPath)
1 2 File file3 = new File("D:\\JavaLearning" ,"JavaSenior" ); File file4 = new File(file3,"hi.txt" );
在idea中,对于相对路径,文件创建于此文件所在的Module文件夹下。
常见方法 获取File类文件信息 1 2 3 4 5 6 7 8 9 10 11 public String getAbsolutePath () :获取绝对路径public String getPath () :获取路径public String getName () :获取名称public String getParent () :获取上层文件目录路径。若无,返回null public long length () :获取文件长度(即:字节数)。不能获取目录的长度。public long lastModified () :获取最后一次的修改时间,毫秒值 public String[] list () :获取指定目录下的所有文件或者文件目录的名称数组public File[] listFiles () :获取指定目录下的所有文件或者文件目录的File数组
判断File类文件信息 1 2 3 4 5 6 public boolean isDirectory () :判断是否是文件目录public boolean isFile () :判断是否是文件public boolean exists () :判断是否存在public boolean canRead () :判断是否可读public boolean canWrite () :判断是否可写public boolean isHidden () :判断是否隐藏
对File类实现硬盘文件创建 1 2 3 4 5 6 7 8 public boolean createNewFile () :创建文件。若文件存在,则不创建,返回false public boolean mkdir () :创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。public boolean mkdirs () :创建文件目录。如果此文件目录存在,就不创建了。如果上层文件目录不存在,一并创建public boolean delete () :删除文件或者文件夹
遍历所有文件(递归) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public static ArrayList<File> listAllFiles (ArrayList<File> arr, File file) { File[] files = file.listFiles(); for (File data : files){ if (data.isDirectory()){ listAllFiles(arr,data); }else { arr.add(data); } } return arr; }
IO流 基本分类
操作数据类型:字节流,字符流
数据的流向:输入流,输出流
流的角色:节点流,处理流
流的体系
数据读入写出
对于文本文件(.txt; .c; .cpp),使用字符流处理
对于非文本文件(.jpg,.mp3,.avi,.ppt,.doc),使用字节流
基本操作
实例化File类对象,指明要操作的文件(需要读出的文件,需要写入的文件);
提供具体的处理字节(字符)流(输入流、输出流);
数据的读取、写入;
关闭流操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 @Test public void testFileReaderFileWriter () { FileReader fr = null ; FileWriter fw = null ; try { File scrFile = new File("hello.txt" ); File destFile = new File("hello2.txt" ); fr = new FileReader(scrFile); fw = new FileWriter(destFile); char [] cbuf = new char [5 ]; int len; while ((len = fr.read(cbuf)) != -1 ){ fw.write(cbuf,0 ,len); } } catch (IOException e) { e.printStackTrace(); } finally { try { fw.close(); } catch (IOException e) { e.printStackTrace(); } try { fr.close(); } catch (IOException e) { e.printStackTrace(); } } }
控制台输出乱码 对于一个hello.txt
文本,有以下文本内容,并用字符流读取文件,将内容打印输出在控制台。
中南大学在读中南大学在读中南大学在读中南大学在读中南大学在读中南大学在读
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Test public void test1 () { FileInputStream fis = null ; try { fis = new FileInputStream(new File("hello.txt" )); byte [] buffer = new byte [5 ]; int len; while ((len = fis.read(buffer)) != -1 ){ String str = new String(buffer,0 ,len); System.out.print(str); } } catch (IOException e) { e.printStackTrace(); } finally { if (fis != null ){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
最终输出,出现乱码:
中�����学在�����南大�����读中�����学在�����南大�����读中�����学在�����南大�����读
明显,在读取过程中,汉字并不能被连续输出显示。由于是UTF-8编码,所以一个汉字是三个字节,导致被在被长度为5的byte数组接收输出时,会出现断码情况。但是如果将字节再写入到另外一个文本文件,依旧是完整的文本信息,此时字节自动拼接成汉字。
改进 采用ByteArrayOutputStream()
,空参情况下,会新建一个长度32字节的数组,如果加入的内容超过32字节,就会自动进行扩充,保证在文本输出前,不会出现断码情况。
1 2 3 4 5 6 7 public ByteArrayOutputStream () { this (32 ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 @Test public void test2 () { FileInputStream fis = null ; ByteArrayOutputStream baos = null ; try { fis = new FileInputStream(new File("hello.txt" )); baos = new ByteArrayOutputStream(); byte [] buffer = new byte [5 ]; int len; while ((len = fis.read(buffer)) != -1 ){ baos.write(buffer,0 ,len); } System.out.println(baos.toString()); } catch (IOException e) { e.printStackTrace(); } finally { if (baos != null ){ try { baos.close(); } catch (IOException e) { e.printStackTrace(); } } if (fis != null ){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
最终输出文本,无乱码:
中南大学在读中南大学在读中南大学在读中南大学在读中南大学在读中南大学在读
处理流使用 缓冲流 缓冲流BufferedInputStream
、BufferedReader
、BufferedOutputStream
、BufferedWriter
通过设置缓冲区,空间换时间,减少读取写出次数,达到提高效率的目的。具体可以参考:缓冲流如何提高性能 ,感兴趣的顺便可以利用数组实现循环队列,刷一道中等力扣:622. 设计循环队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 @Test public void BufferedStreamTest () { FileInputStream fis = null ; FileOutputStream fos = null ; BufferedInputStream bis = null ; BufferedOutputStream bos = null ; try { File srcFile = new File("wallhaven-oxrq99.jpg" ); File destFile = new File("wallhaven1.jpg" ); fis = new FileInputStream(srcFile); fos = new FileOutputStream(destFile); bis = new BufferedInputStream(fis); bos = new BufferedOutputStream(fos); byte [] buffer = new byte [10 ]; int len; while ((len = bis.read(buffer)) != -1 ) { bos.write(buffer, 0 , len); } } catch (IOException e) { e.printStackTrace(); } finally { if (bos != null ) { try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } if (bis != null ) { try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
转换流
InputStreamReader: 字节 —> 字符 ——— 解码过程
OutputStreamWriter: 字符 —> 字节 ———编码过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 @Test public void test2 () { FileInputStream fis = null ; FileOutputStream fos = null ; try { File file1 = new File("dbcp.txt" ); File file2 = new File("dbcp_gbk.txt" ); fis = new FileInputStream(file1); fos = new FileOutputStream(file2); InputStreamReader isr = new InputStreamReader(fis,"UTF-8" ); OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk" ); char [] cbuf= new char [20 ]; int len; while ((len = isr.read(cbuf)) != -1 ){ osw.write(cbuf,0 ,len); } } catch (IOException e) { e.printStackTrace(); } finally { if (fos != null ){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if (fis != null ){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
对象流
用于存储和读取基本数据类型或者对象的处理流
对象的序列化就是将对象转换成二进制数据流的一种实现手段,通过将对象序列化,可以方便的实现对象的传输及保存。当使用对象流写入或者读取对象的时候,必须保证该对象是序列化 的,这样是为了保证对象能够正确的写入文件,并能够把对象正确的读回程序。在Java中提供了ObejctInputStream
和ObjectOutputStream
这两个类用于序列化对象的操作。ObjectOutputStream
和ObjectInputStream
不能序列化static
和transient
修饰的成员变量。
序列化条件:
需要实现接口:Serializable;(该接口没有任何属性和方法,仅仅作为序列化的表示)
需要当前类提供一个全局常量:serialVersionUID;
除了需要读入的类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是序列化的。(默认情况下,基本数据类型也是可序列化的)。
RandomAccessFile类 RandomAccessFile
既可以读取文件内容,也可以向文件输出数据。由于 RandomAccessFile 可以从任意位置访问文件,所以在只需要访问文件部分内容的情况下,使用 RandonAccessFile 类是一个很好的选择。
RandomAccessFile
一共有两个构造器,形参1都是为了提供文件,形参2则是指定文件读写类型:
r
: 以只读形式打开
rw
: 打开以便读取和写入
rwd
: 打开以便读取和写入,同步文件内容的更新
rws
: 打开以便读取和写入,同步文件内容和元数据的更新
一般常用:r
和 rw
1 2 3 4 5 public RandomAccessFile (String name, String mode) throws FileNotFoundException { this (name != null ? new File(name) : null , mode); }
1 2 3 4 5 public RandomAccessFile (File file, String mode) throws FileNotFoundException { this (file, mode, false ); }
该类存在一个seek指针(默认为0),实现从指针处开始向后覆盖数据。对于初始文本数据:abcdefghijk,将指针改为3后写入xyz,最后文本数据为:abcxyzghijk
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Test public void test2 () { RandomAccessFile raf1 = null ; try { raf1 = new RandomAccessFile("hello.txt" ,"rw" ); raf1.seek(3 ); raf1.write("xyz" .getBytes()); } catch (IOException e) { e.printStackTrace(); } finally { if (raf1 != null ){ try { raf1.close(); } catch (IOException e) { e.printStackTrace(); } } } }