File 文件类 创建文件对象的构造方法:
方法
功能
File(String pathname)
通过将给定路径名字符串转换成抽象路径名来创建一个新 File 实例。(其中路径可以是相对路径也可以是绝对路径)
File(File parent, String child)
通过给定的父抽象路径名和子路径名字符串创建一个新的File实例。
File(String parent, String child)
根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
File(URI uri)
通过将给定的 file: URI 转换成一个抽象路径名来创建一个新的 File 实例。
文件常用方法:
方法
功能
exists()
判断文件是否存在
isDirectory()
判断是否是文件夹
isFile()
判断是否是文件
length()
获取文件的长度
lastModified()
文件最后修改时间的 long 值,可以配合 Date 类输出直观时间
setLastModified(long time)
设置文件修改时间为 time
renameTo(File dest)
文件重命名
list()
以字符串数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
listFiles()
以文件数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
getParent()
以字符串形式返回获取所在文件夹
getParentFile()
以文件形式返回获取所在文件夹
mkdir()
创建文件夹,如果父文件夹不存在,创建就无效
mkdirs()
创建文件夹,如果父文件夹不存在,就会创建父文件夹
creatNewFile()
创建一个空文件,如果父文件夹不存在,就会抛出异常。所以在创建一个空文件之前,通常会先创建父目录:filename.getParentFile().mkdirs()
listRoots()
列出所有的盘符 c: d: e: 等等
delete()
删除文件
deleteOnExit()
JVM结束的时候,删除文件,常用于临时文件的删除
Stream 流 Java 语言定义了许多类专门负责各种方式的输入或者输出,这些类都被放在 java.io 包中。
流的作用:为了永久性的保存数据。
分类:根据数据流向的不同分为输入流和输出流;根据处理数据类型的不同分为字符流和字节流。其中,所有输入流类都是抽象类 InputStream (字节输入流),或者抽象类 Reader (字符输入流)的子类;而所有输出流都是抽象类 OutputStream (字节输出流)或者 Writer (字符输出流)的子类。
文件字节流 InputStream 是字节输入流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。 FileInputStream 是 InputStream 子类,以 FileInputStream 为例进行文件读取:
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 package stream; import java.io.File;import java.io.FileInputStream;import java.io.IOException; public class TestStream { public static void main (String[] args) { try { File f =new File("d:/lol.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(); } } }
一些常用方法:
方法
功能
public void close() throws IOException{}
关闭此文件输入流并释放与此流有关的所有系统资源。抛出 IOException 异常。
protected void finalize()throws IOException {}
这个方法清除与该文件的连接。确保在不再引用文件输入流时调用其 close 方法。抛出 IOException 异常。
public int read(int r)throws IOException{}
这个方法从 InputStream 对象读取指定字节的数据。返回为整数值。返回下一字节数据,如果已经到结尾则返回 -1。
public int read(byte[] r) throws IOException{}
这个方法从输入流读取 r.length 长度的字节。返回读取的字节数。如果是文件结尾则返回 -1。
public int available() throws IOException{}
返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取的字节数。返回一个整数值。
FileOutputStream OutputStream是字节输出流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。 FileOutputStream 是 OutputStream 子类,以 FileOutputStream 为例向文件写出数据。(注: 如果文件d:/lol2.txt不存在,写出操作会自动创建该文件。但是如果是文件 d:/xyz/lol2.txt,而目录xyz又不存在,会抛出异常。)
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 package stream; import java.io.File;import java.io.FileOutputStream;import java.io.IOException; public class TestStream { public static void main (String[] args) { try { File f = new File("d:/lol2.txt" ); byte data[] = { 88 , 89 }; FileOutputStream fos = new FileOutputStream(f); fos.write(data); fos.close(); } catch (IOException e) { e.printStackTrace(); } } }
一些常用方法:
方法
功能
public void close() throws IOException{}
关闭此文件输入流并释放与此流有关的所有系统资源。抛出 IOException 异常。
protected void finalize()throws IOException {}
这个方法清除与该文件的连接。确保在不再引用文件输入流时调用其 close 方法。抛出 IOException 异常。
public void write(int w)throws IOException{}
这个方法把指定的字节写到输出流中。
public void write(byte[] w)
把指定数组中 w.length 长度的字节写到 OutputStream 中。
文件字符流 FileReader FileReader 是 Reader 子类,该类按字符读取流中数据。可以通过以下几种构造方法创建需要的对象。
FileReader(File file)
FileReader(FileDescriptor fd)
FileReader(String fileName)
以 FileReader 为例进行文件读取:
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 package stream; import java.io.File;import java.io.FileReader;import java.io.IOException; public class TestStream { public static void main (String[] args) { File f = new File("d:/lol.txt" ); try (FileReader fr = new FileReader(f)) { char [] all = new char [(int ) f.length()]; fr.read(all); for (char b : all) { System.out.println(b); } } catch (IOException e) { e.printStackTrace(); } } }
一些常用方法:
方法
功能
public int read() throws IOException
读取单个字符,返回一个int型变量代表读取到的字符。
public int read(char [] c, int offset, int len)
读取字符到c数组,返回读取到字符的个数。
FileWriter FileWriter 是 Writer 的子类,该类按字符向流中写入数据。可以通过以下几种构造方法创建需要的对象。
append参数:若为 true 则在文件末尾追加,若为 false 覆盖文件内容。
以 FileWriter 为例把字符串写入到文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package stream; import java.io.File;import java.io.FileWriter;import java.io.IOException; public class TestStream { public static void main (String[] args) { File f = new File("d:/lol2.txt" ); try (FileWriter fr = new FileWriter(f)) { String data="abcdefg1234567890" ; char [] cs = data.toCharArray(); fr.write(cs); } catch (IOException e) { e.printStackTrace(); } } }
一些常用方法:
方法
功能
public void write(int c) throws IOException
写入单个字符c。
public void write(char [] c, int offset, int len)
写入字符数组中开始为offset长度为len的某一部分。
public void write(String s, int offset, int len)
写入字符串中开始为offset长度为len的某一部分。
中文问题 为了能够正确的读取中文内容
以“中”为例子:
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 package stream; import java.io.File;import java.io.FileInputStream;import java.io.IOException; public class TestStream { public static void main (String[] args) { File f = new File("E:\\project\\j2se\\src\\test.txt" ); try (FileInputStream fis = new FileInputStream(f);) { byte [] all = new byte [(int ) f.length()]; fis.read(all); System.out.println("文件中读出来的数据是:" ); for (byte b : all) { int i = b&0x000000ff ; System.out.println(Integer.toHexString(i)); } System.out.println("把这个数字,放在GBK的棋盘上去:" ); String str = new String(all,"GBK" ); System.out.println(str); } catch (IOException e) { e.printStackTrace(); } } }
用FileReader 字符流正确读取中文 FileReader 得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了。而 FileReader 使用的编码方式是 Charset.defaultCharset() 的返回值,如果是中文的操作系统,就是 GBK。FileReader 是不能手动设置编码方式的,为了使用其他的编码方式,只能使用 InputStreamReader 来代替,像这样:
1 new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8" ));
以“中”为例子:
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 package stream; import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.UnsupportedEncodingException;import java.nio.charset.Charset; public class TestStream { public static void main (String[] args) throws UnsupportedEncodingException, FileNotFoundException { File f = new File("E:\\project\\j2se\\src\\test.txt" ); System.out.println("默认编码方式:" +Charset.defaultCharset()); 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) { e.printStackTrace(); } 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) { e.printStackTrace(); } } }
解释: 为什么中字前面有一个? 如果是使用记事本另存为UTF-8的格式,那么在第一个字节有一个标示符,叫做 BOM 用来标志这个文件是用 UTF-8 来编码的。
关闭流的方式 在 try 中关闭 在try的作用域里关闭文件输入流,在前面的示例中都是使用这种方式,这样做有一个弊端; 如果文件不存在,或者读取的时候出现问题而抛出异常,那么就不会执行这一行关闭流的代码,存在巨大的资源占用隐患。 不推荐使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package stream; import java.io.File;import java.io.FileInputStream;import java.io.IOException; public class TestStream { public static void main (String[] args) { try { File f = new File("d:/lol.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(); } } }
在 finally 中关闭 这是标准的关闭流的方式:
首先把流的引用声明在 try 的外面,如果声明在 try 里面,其作用域无法抵达 finally。
在 finally 关闭之前,要先判断该引用是否为空。
关闭的时候,需要再一次进行 try catch 处理。
这是标准的严谨的关闭流的方式,但是看上去很繁琐,所以写不重要的或者测试代码的时候,都会采用上面的有隐患try的方式,因为不麻烦~
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 package stream; import java.io.File;import java.io.FileInputStream;import java.io.IOException; public class TestStream { public static void main (String[] args) { File f = new File("d:/lol.txt" ); FileInputStream fis = null ; try { fis = new FileInputStream(f); byte [] all = new byte [(int ) f.length()]; fis.read(all); for (byte b : all) { System.out.println(b); } } catch (IOException e) { e.printStackTrace(); } finally { if (null != fis) try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
使用 try() 的方式 把流定义在 try() 里, try, catch 或者 finally 结束的时候,会自动关闭。这种编写代码的方式叫做 try-with-resources, 这是从 JDK7 开始支持的技术。所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在 try() 中进行实例化。 并且在try, catch, finally 结束的时候自动关闭,回收相关资源。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package stream; import java.io.File;import java.io.FileInputStream;import java.io.IOException; public class TestStream { public static void main (String[] args) { File f = new File("d:/lol.txt" ); try (FileInputStream fis = new FileInputStream(f)) { byte [] all = new byte [(int ) f.length()]; fis.read(all); for (byte b : all) { System.out.println(b); } } catch (IOException e) { e.printStackTrace(); } } }
缓存流 以介质是硬盘为例,字节流和字符流的弊端: 在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。
为了解决以上弊端,采用缓存流。 缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中读取。
缓存流在写入数据的时候,会先把数据写入到缓存区,直到缓存区达到一定的量,才把这些数据,一起写入到硬盘中去。按照这种操作模式,就不会像字节流,字符流那样每写一个字节都访问硬盘,从而减少了IO操作。
使用缓存流读取数据 缓存字符输入流 BufferedReader 可以一次读取一行数据:
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 package stream; import java.io.BufferedReader;import java.io.File;import java.io.FileReader;import java.io.IOException; public class TestStream { public static void main (String[] args) { File f = new File("d:/lol.txt" ); try ( FileReader fr = new FileReader(f); BufferedReader br = new BufferedReader(fr); ) { while (true ) { String line = br.readLine(); if (null == line) break ; System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } }
使用缓存流写出数据 PrintWriter 缓存字符输出流, 可以一次写出一行数据:
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 package stream; import java.io.File;import java.io.FileWriter;import java.io.IOException;import java.io.PrintWriter; public class TestStream { public static void main (String[] args) { File f = new File("d:/lol2.txt" ); try ( FileWriter fw = new FileWriter(f); PrintWriter pw = new PrintWriter(fw); ) { pw.println("garen kill teemo" ); pw.println("teemo revive after 1 minutes" ); pw.println("teemo try to garen, but killed again" ); } catch (IOException e) { e.printStackTrace(); } } }
flush 有的时候,需要立即把数据写入到硬盘,而不是等缓存满了才写出去。 这时候就需要用到 flush:
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 package stream; import java.io.File;import java.io.FileWriter;import java.io.IOException;import java.io.PrintWriter;public class TestStream { public static void main (String[] args) { File f =new File("d:/lol2.txt" ); try (FileWriter fr = new FileWriter(f);PrintWriter pw = new PrintWriter(fr);) { pw.println("garen kill teemo" ); pw.flush(); pw.println("teemo revive after 1 minutes" ); pw.flush(); pw.println("teemo try to garen, but killed again" ); pw.flush(); } catch (IOException e) { e.printStackTrace(); } } }
数据流 DataInputStream 数据输入流 DataOutputStream 数据输出流
直接进行字符串的读写 使用数据流的 writeUTF() 和 readUTF() 可以进行数据的格式化顺序读写。如本例,通过 DataOutputStream 向文件顺序写出布尔值,整数和字符串。然后再通过 DataInputStream 顺序读入这些数据。
注:要用 DataInputStream 读取一个文件,这个文件必须是由 DataOutputStream 写出的,否则会出现 EOFException,因为 DataOutputStream 在写出的时候会做一些特殊标记,只有 DataInputStream 才能成功的读取。
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 package stream; import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException; public class TestStream { public static void main (String[] args) { write(); read(); } private static void read () { File f =new File("d:/lol.txt" ); try ( FileInputStream fis = new FileInputStream(f); DataInputStream dis =new DataInputStream(fis); ){ boolean b= dis.readBoolean(); int i = dis.readInt(); String str = dis.readUTF(); System.out.println("读取到布尔值:" +b); System.out.println("读取到整数:" +i); System.out.println("读取到字符串:" +str); } catch (IOException e) { e.printStackTrace(); } } private static void write () { File f =new File("d:/lol.txt" ); try ( FileOutputStream fos = new FileOutputStream(f); DataOutputStream dos =new DataOutputStream(fos); ){ dos.writeBoolean(true ); dos.writeInt(300 ); dos.writeUTF("123 this is gareen" ); } catch (IOException e) { e.printStackTrace(); } } }
对象流 对象流指的是可以直接把一个对象以流的形式传输给其他的介质,比如硬盘。
一个对象以流的形式进行传输,叫做序列化。 该对象所对应的类,必须是实现 Serializable 接口。
序列化一个对象 创建一个 Hero 对象,设置其名称为 garen。把该对象序列化到一个文件 garen.lol。然后再通过序列化把该文件转换为一个 Hero 对象。
注:把一个对象序列化有一个前提是:这个对象的类,必须实现了 Serializable 接口。
TestStream.java
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 package stream; import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream; import charactor.Hero; public class TestStream { public static void main (String[] args) { Hero h = new Hero(); h.name = "garen" ; h.hp = 616 ; File f =new File("d:/garen.lol" ); try ( FileOutputStream fos = new FileOutputStream(f); ObjectOutputStream oos =new ObjectOutputStream(fos); FileInputStream fis = new FileInputStream(f); ObjectInputStream ois =new ObjectInputStream(fis); ) { oos.writeObject(h); Hero h2 = (Hero) ois.readObject(); System.out.println(h2.name); System.out.println(h2.hp); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
Hero.java
1 2 3 4 5 6 7 8 9 10 11 package charactor; import java.io.Serializable; public class Hero implements Serializable { private static final long serialVersionUID = 1L ; public String name; public float hp; }
System.in/out System.out 是常用的在控制台输出数据的 System.in 可以从控制台输入数据
System.in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package stream; import java.io.IOException;import java.io.InputStream; public class TestStream { public static void main (String[] args) { try (InputStream is = System.in;) { while (true ) { int i = is.read(); System.out.println(i); } } catch (IOException e) { e.printStackTrace(); } } }
Scanner读取字符串 使用 System.in.read 虽然可以读取数据,但是很不方便。使用 Scanner 就可以逐行读取了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package stream; import java.util.Scanner; public class TestStream { public static void main (String[] args) { Scanner s = new Scanner(System.in); while (true ){ String line = s.nextLine(); System.out.println(line); } } }
Scanner从控制台读取整数 java.util.Scanner 是 Java5 的新特征,我们可以通过 Scanner 类来获取用户的输入。
使用Scanner从控制台读取整数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package stream; import java.util.Scanner; public class TestStream { public static void main (String[] args) { Scanner s = new Scanner(System.in); int a = s.nextInt(); System.out.println("第一个整数:" +a); int b = s.nextInt(); System.out.println("第二个整数:" +b); } }
一些补充 上述常用流关系图
flush() 和 close() 的区别
什么情况下使用字符流?
字符流也可以拷贝文本文件,但不推荐使用。 因为读取时会把字节转为字符,写出时还要把字符转回字节。
程序需要读取一段文本,或者需要写出一段文本的时候可以使用字符流。
读取的时候是按照字符的大小读取的,不会出现半个中文。
写出的时候可以直接将字符串写出,不用转换为字节数组。