File类
File类的理解
- File类位于java.io包下。
- File类的一个对象,对应于操作系统下的一个文件或一个文件目录
- File类中声明了新建、删除、获取名称、重命名等方法,并没有涉及到文件内容的读写操作。要想实现文件内容的读写,需要使用io流。
- File类的对象,通常是作为io流操作的文件的端点出现。
- 代码层面,将File类对象作为参数传递到IO流相关类的构造器中。
构造器
- File(String pathname) :以pathname为路径创建File对象,可以是绝对路径或者相对路径
- File(String parent, String child):以parent为父路径,child为子路径创建file对象
- File(File parent, String child) 根据一个父File对象和子文件路径创建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
| public class FileTest { @Test public void test1(){
File file1 = new File("d:/io\\hello.txt"); File file2 = new File("abc"); } @Test public void test2(){ File file1 = new File("d:\\io","abc.txt"); File file2 = new File("abc","ab"); File file3 = new File(file2,"ab"); } }
|
方法
获取文件和目录基本信息
- String getName():获取名称
- String getPath():获取路径
- String getAbsolutePaht():获取绝对路径
- File getAbsoluteFile():获取绝对路径表示的文件
- String getParent():获取上层文件目录路径。不能获取目录的长度
- long length():获取文件长度(字节数).不能获取目录的长度
- long lastModified():获取最后一次的修改时间,毫秒值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Test public void test(){ File file = new File("hello.txt"); System.out.println(file.getName()); System.out.println(file.getPath()); System.out.println(file.getAbsolutePath()); System.out.println(file.getAbsoluteFile()); System.out.println(file.getParent()); System.out.println(file.length()); System.out.println(file.lastModified());
File file1 = new File("D:\\javaSE\\Chapter15_file\\hello.txt"); System.out.println(file1.getName()); System.out.println(file1.getPath()); System.out.println(file1.getAbsolutePath()); System.out.println(file1.getAbsoluteFile()); System.out.println(file1.getParent()); System.out.println(file1.length()); System.out.println(file1.lastModified()); }
|
列出目录的下一级
- String[] list():返回一个String数组,表示该File目录中的所有子文件或目录。
- File[] listFiles():返回一个File数组,表示该File目录中的所有子文件或目录。
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Test public void test2(){ File file1 = new File("D:\\javaSE\\javaSE"); String[] fileArr = file1.list(); for(String s:fileArr){ System.out.println(s); }
File[] files = file1.listFiles(); for(File f:files){ System.out.println(f); } }
|
重命名
- file1.renamTo(file2):把文件重命名为指定的文件路径。file1必须存在且file2不存在
1 2 3 4 5 6 7 8
| @Test public void test3(){ File file1 = new File("hello.txt"); File file2 = new File("D:\\javaSE\\JavaSE\\Chapter15_file\\hello2.txt");
boolean renameSuccess = file1.renameTo(file2); System.out.println(); }
|
判断功能的方法
- boolean exits():此File表示的文件或目录是否实际存在
- boolean isDirectory():此File表示的是否为目录
- boolean isFile():此File表示的是否为文件
- boolean canRead():判断是否可读
- boolean canWrite():判断是否可写
- boolean isHidden():判断是否隐藏
1 2 3 4 5 6 7 8 9 10
| @Test public void test4(){ File file1 = new File("hello2.txt"); System.out.println(file1.exists()); System.out.println(file1.isDirectory()); System.out.println(file1.isFile()); System.out.println(file1.canRead()); System.out.println(file1.canWrite()); System.out.println(file1.isHidden()); }
|
创建和删除类型
- boolean createNewFile():创建文件。若文件存在,则不创建,返回false
- boolean mkdir():创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上册目录不存在,也不创建
- boolean mkdirs():创建文件目录。如果上层文件目录不存在,一并创建
- boolean delete():删除文件或文件夹
- 注意:java中的删除不走回收站。要删除一个文件目录,请主要该文件目录内不能包含文件或者文件目录
IO流
java中对于数据的输入/输出操作以“流”的方式进行,可以看作是一种数据的流动
流的分类
- 流向的不同:输入流、输出流
- 处理单位的不同:字节流、字符流
- 流的角色的不同:节点流、处理流
流的API
IO流共涉及40多个类,实际上非常规则,都是从如下4个抽象基类派生的。
(抽象基类) |
输入流 |
输出流 |
字节流 |
InputStream |
OutputStream |
字符流 |
Reader |
Writer |
节点流
字符流
FileReader\FileWriter的使用
执行步骤:
- 创建读或写的File类对象
- 创建输入流或输出流
- 具体的读入或写出的过程
- 读入:read(char[] cbuffer)
- 写出:write(String str)/ write(char[] cbuffer,0,len)
- 关闭流资源
注意点:
因为涉及流资源关闭操作,所以出现异常的花,需要使用try-catch-finally的方式来处理异常
对于输入流来讲,要求File类的对象对应的物理磁盘上的文件必须存在。否则会报FileNotFoundException
对于输出流来讲,File类的对象对应的物理磁盘上的文件可以不存在。
- 如果此文件不存在,则在输出的过程中,会自动创建此文件,并写出数据到此文件中。
- 如果此文件存在,使用FileWriter(file file)或FileWriter(File file, false):输出数据过程中,会创建同名的文件对现有的文件进行覆盖。
- FileWriter(File file, true):输出数据过程中,会在现有的文件的末尾追加写出的内容。
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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| @Test public void test() throws IOException { FileReader fileReader = null; try { File file1 = new File("hello.txt");
fileReader = new FileReader(file1);
char[] cbuffer = new char[5]; int len; while((len=fileReader.read(cbuffer))!= -1){ for(int i =0; i<len;i++){ System.out.println(cbuffer[i]); } }
} catch (IOException e) { throw new RuntimeException(e); } finally { try { if(fileReader != null){ fileReader.close(); } } catch (IOException e) { throw new RuntimeException(e); } } }
@Test public void test2() { FileWriter fw = null; try { File file = new File("info.txt"); fw = new FileWriter(file,false);
fw.write("I love"); fw.write("you love"); fw.write("xixi"); } catch (IOException e) { throw new RuntimeException(e); } finally { try { if(fw!=null){ fw.close(); } } catch (IOException e) { throw new RuntimeException(e); } } }
@Test public void test1() { FileReader fr = null; FileWriter fw = null; try { File srcFile = new File("hello.txt"); File destFile = new File("hello_copy.txt");
fr = new FileReader(srcFile); fw = new FileWriter(destFile);
char[] cbuffer = new char[5]; int len; while ((len = fr.read(cbuffer)) != -1) { fw.write(cbuffer, 0, len); } } catch (IOException e) { throw new RuntimeException(e); } finally { try { if(fw!=null){ fw.close(); } } catch (IOException e) { throw new RuntimeException(e); } try { if(fr!=null) { fr.close(); } } catch (IOException e) { throw new RuntimeException(e); } } }
|
字节流
使用步骤:
- 创建读或写的File类对象
- 创建输入流或输出流
- 具体的读入或写出的过程
- 读入:read(byte[] buffer)
- 写出:write(byte[] buffer,0,len)
- 关闭流资源
注意点:
- 在文件流的注意点基础之上。 字符流只能用来操作文本文件,不能用来处理非文本文件。
- 对于字节流,通常是用来处理非文本文件。但是涉及到文本文件的复制操作,也可以使用字节流。
说明:
文本文件:.txt、 .java、.c
非文本文件:.doc 、 .xls 、.jpg、.pdf 、.mp3
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
| public class FileStreamTest{ @Test public void test() { FileInputStream fis = null; FileOutputStream fos = null; try { File srcFile = new File("xxx.jpg"); File desFile = new File("xxx_copy.jpg");
fis = new FileInputStream(srcFile); fos = new FileOutputStream(desFile);
byte[] buffer = new byte[1024]; int len; while((len = fis.read(buffer))!=-1){ fos.write(buffer,0,len); }
} catch (IOException e) { throw new RuntimeException(e); } finally { try { if(fos!=null){ fos.close(); } } catch (Exception e) { throw new RuntimeException(e); } try { if(fos!=null){ fis.close(); } } catch (Exception e) { throw new RuntimeException(e); } } } }
|
缓冲流
抽象基类 |
节点流(文件流) |
缓冲流 |
InputStream |
FileInputStream |
BufferedInputStream |
OutputStream |
FileOutputStream |
BufferedOutputStream |
Reader |
FileReader |
BufferedReader |
Writer |
FileWriter |
BufferedWriter |
缓冲流的作用
减少与磁盘的交互,提升文件读写的效率。
缓冲区:内部提供了一个数组,将读取或写出的数据,现在此数组中缓冲。达到一定程度时,集中性的写出。
4个缓冲流
处理非文本文件的字节流: 方法
BufferedInputStream read(byte[] buffer)
BufferedOutputStream write(byte[] buffer,0,len)
处理文本文件的字符流
- BufferedReader read(char[] cbuffer) / readLine()
- BufferedWriter write(char[] cbuffer, 0, len)
实现步骤
创建File对象、流的对象(包括文件流、缓冲流)
使用缓冲流实现读取数据或写出数据的过程
读取:int read(char[] cbuf/byte[] buffer) :每次将数据读入到cbuf/buffer数组中,并返回读入到数组中
写出: void write(String str)/write(char[] cbuf):将str或cbuf写出到文件中
void write(byte[] buffer) 将byte写出到文件中
关闭资源
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
| public class BufferInputTest { @Test public void test() { FileInputStream fis = null; FileOutputStream fos = null; BufferedInputStream bis = null; BufferedOutputStream bos = null; try { File srcFile = new File("xxx.jpg"); File desFile = new File("xxx_copy.jpg");
fis = new FileInputStream(srcFile); fos = new FileOutputStream(desFile);
bis = new BufferedInputStream(fis); bos = new BufferedOutputStream(fos);
byte[] buffer = new byte[1024]; int len; while((len = bis.read(buffer))!=-1){ bos.write(buffer,0,len); }
} catch (IOException e) { throw new RuntimeException(e); } finally { try { if(bis!=null){ bis.close(); } } catch (Exception e) { throw new RuntimeException(e); } try { if(bos!=null){ bos.close(); } } catch (Exception e) { throw new RuntimeException(e); } } } }
|
转换流
字符编码:字符、字符串、字符数组–》字节、字节数组
字符解码:字节、字节数组–》字符、字符串、字符数组
如果希望程序在读取文本时,不出现乱码
解码时使用的字符集必须与当初编码时使用的字符集一致
解码集必须要与编码集兼容。
作用:实现字节与字符之间的转换
API:
InputStreamReader:将一个输入型的字节流转换为输入型的字符流
OutputStreamWriter:讲一个输出型的字符流转换为输出型的字节流
关于字符集的理解
ascii:主要用来存储a,b,c英文字符和1,2,3常用标点字符。每个字符1个字节。
iso-8859-1:了解,每个字符占用1个字符。向下兼容ascii
gbk:用来存储包括中文简体繁体,a,b,c等英文字符和1,2,3,常用的标点符号等字符。中文字符使用2个字节,向下兼容ascii。英文1个字节。
utf-8:可以用来存储世界范围内主要的语言的所有的字符。使用1-4个不等的字节表示一个字符。中文使用3个字节,英文1个。
内存中的字符
一个字符(char)占用2个字节。在内存使用的字符集称为Unicode字符集。
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 test2() throws IOException{ File file1 = new File("xxx_gbk.txt"); File file2 = new File("xxx_gbk2utf8"); FileInputStream fis = new FileInputStream(file1); InputStreamReader isr = new InputStreamReader(fis,"GBK");
FileOutputStream fos = new FileOutputStream(file2); OutputStreamWriter oos = new OutputStreamWriter(fos,"utf8");
char[] cBuffer = new char[1024]; int len; while((len = isr.read(cBuffer))!=-1){ oos.write(cBuffer,0,len); } System.out.println("操作完成");
oos.close(); isr.close(); }
|
对象流
说明
考虑将内存中定义的变量保存在文件中
数据流(只支持基本数据类型和字符串的读写,而不支持其他jav对象的类型)
- DataOutputStream:将内存中基本数据类型、String类型的变量写入具体的文件中
- DataInputStream:将文件中保存的数据还原为内存的基本数据类型、String类型的变量。
对象流
- ObjectOutputStream:将java基本数据类型和对象写入字节输出流中。通过在流中使用文件可以实现java各种基本数据类型的数据以及对象的持久存储
- ObjectInputStream:ObjectInputStream对以前使用ObjectOutputStream写出的基本数据类型的数据和对象进行读入操作,保存在内存中。
对象的序列化机制
对象序列化机制允许把内存中java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。//当其他程序获取了这种二进制流,就可以恢复成原来的java对象。
- 序列化过程:ObjectOutputStream流实现。将内存中的java对象保存在文件中或通过网络传输出去
- 反序列化过程:使用ObjectInputStream实现。将文件中的数据或网络传输过来的数据还原为内存中的java的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class ObjectOutputTest { @Test public void test1() throws IOException { File file = new File("xx.txt"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeUTF("xixihaha"); oos.writeObject("xixihaha"); oos.flush(); oos.close(); } @Test public void test2() throws IOException, ClassNotFoundException { File file = new File("xx.txt"); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); String str1 = ois.readUTF(); String str2 = (String) ois.readObject(); System.out.println(str1); System.out.println(str2);
ois.close(); } }
|
自定义类实现序列化的要求
- 自定义类需要实现接口:Serializable
- 要求自定义类声明一个全局常量:static final long serialVersionUID = 42234234L;用于唯一的标识当前的类
- 要求自定义类的各个属性必须是可序列化的。
- 对于基本数据类型的属性:默认可序列化
- 对于引用数据类型:需要实现Serializable接口
注意点:
如果不声明全局常量,系统会自动声明生产一个针对于当前类的serialVersionUID。
如果修改此类的话,会导致serialVersionUID变换,进而导致反序列化时,出现InvalidClassException异常
类中的属性如果声明为transient或static,则不会序列化。
其他流
标准输入流、标准输出流、system.in、system.out