11.1 File类的使用
File类是文件和目录的抽象表示形式。File能新建、删除、重命名文件和目录,但不能访问文件内容。
public File(String pathname)public File(File parent,String child)
Windows和DOS系统使用“\”,UNIX和URL使用“/”,File提供静态常量separator根据操作系统动态的提供分隔符。
获取功能:public String getAbsolutePath()public String getPath()public String getName()public String getParent()public long length() :获取文件长度(即:字节数)。public long lastModified() :获取最后一次的修改时间,毫秒值public String[] list() :获取指定目录下的所有文件或者目录的名称数组public File[] listFiles() :获取指定目录下的所有文件或者目录的File数组判断功能:public boolean isDirectory()public boolean isFile()public boolean exists()public boolean canRead()public boolean canWrite()public boolean isHidden()创建、删除、重命名:public boolean createNewFile() :创建文件。若文件存在,则不创建,返回falsepublic boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建public boolean delete():要删除的文件目录内不能包含文件或者文件目录public boolean renameTo(File dest):把文件重命名为指定的文件路径
File dir1 = new File("D:/IOTest/dir1");if (!dir1.exists()) {dir1.mkdirs();}// 创建以dir1为父目录,名为"test.txt"的File对象File file = new File(dir1, "test.txt");if (!file.exists()) {file.createNewFile();}
11.2 IO流及流的分类
I/O技术用来处理设备之间的数据传输,如读写文件、网络通讯等。
- 输入input:读取外部数据到内存中。
- 输出output:将内存数据输出。
按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)。字节流用于处理非文本数据,字符流用于处理文本数据。
- 字节流操作字节,比如:.mp3,.avi,.rmvb,mp4,.jpg,.doc,.ppt, .excel
- 字符流操作字符,比如:.txt,.java,.c,.cpp
按流的角色的不同分为:节点流,处理流。节点流(文件流):直接从数据源或目的地读写数据;处理流:不直接连接到数据源或目的地,而是“连接”在已存在的节点流或处理流之上,通过对数据的处理为程序提供更为强大的读写功能。在如下所示的IO流体系表中,仅访问文件的流是节点流,其他流均为套在其他流上的处理流。
程序中打开的文件 IO 资源不属于内存里的资源,垃圾回收机制无法回收该资源,所以应该显式关闭文件 IO 资源。
InputStream:int read():读取下一个字节,返回[0, 255]内的 int 字节值。如果到达流末尾则返回 -1。int read(byte[] b)将最多 b.length 个字节的数据读入 byte 中,以整数形式返回实际读取的字节数。如果到达流末尾则返回值 -1。int read(byte[] b, int off,int len)将输入流中最多 len 个数据字节读入 byte 数组。Reader:int read()读取单个字符。返回[0, 65535]内的 int 字节值,如果已到达流的末尾,则返回 -1int read(char[] cbuf)int read(char[] cbuf,int off,int len)OutputStreamvoid write(int b)向输出流写入一个字节。要写入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。void write(byte[] b,int off,int len)将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。public void flush()throws IOException 刷新此输出流并强制写出所有缓冲的输出字节Writervoid write(int c)写入 16 个低位,16 高位被忽略。 即写入0 到 65535 之间的Unicode码。void write(String str)写入字符串。public void close() throws IOException 关闭该流并释放与该流关联的所有系统资源。
11.3 节点流(或文件流)
FileReader fr = null;try {fr = new FileReader(new File("c:\\test.txt")); // 1.建立一个流对象,将已存在的一个文件加载进流char[] buf = new char[1024]; // 2.创建一个临时存放数据的数组int len; // 这里不可用buf.length,因为可能读不满while ((len = fr.read(buf)) != -1) // 3.调用流对象的读取方法将流中的数据读入到数组中System.out.print(new String(buf, 0, len));} catch (IOException e) {System.out.println("read-Exception :" + e.getMessage());} finally {if (fr != null) {try {fr.close(); // 必须关闭流} catch (IOException e) {System.out.println("close-Exception :" + e.getMessage());}}}
如果使用构造器FileOutputStream(file,true),则目录下的同名文件不会被覆盖, 在文件内容末尾追加内容。当不表明第二个参数时默认为false,即目录下同名文件将被覆盖。在读取文件时,必须保证该文件已存在,否则报异常。
11.4 缓冲流
为了提高数据读写的速度,缓冲流会创建一个内部缓冲区数组,缺省使用8192个字节(8Kb)的缓冲区。
当使用BufferedInputStream读取字节文件时,会一次性从文件中读取8192个(8Kb),存在缓冲区中,直到缓冲区装满了,才重新从文件中读取下一个8192个字节数组。
向流中写入字节时,不会直接写到文件,先写到缓冲区中直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里。使用方法 flush()可以强制将缓冲区的内容全部写入输出流。
关闭流时要从外层流向内层流逐层关闭。在该方法中,关闭最外层流也会相应关闭内层节点流。如果是带缓冲区的流对象的close()方法,不但会关闭流,还会在关闭流之前刷新缓冲区。
11.5 转换流与字符编码
转换流提供了在字节流和字符流之间的转换,使得在向外部存储设备操作时为字节流,程序内操作时以字符流处理。字节流中的数据都是字符时,转成字符流操作更高效。很多时候我们使用转换流来处理文件乱码问题。实现编码和解码的功能。
- InputStreamReader:将InputStream转换为Reader
- OutputStreamWriter:将Writer转换为OutputStream

public InputSreamReader(InputStream in,String charsetName) // charsetName指明转换编码方式
常见的编码表:ASCII:美国标准信息交换码。用一个字节的7位可以表示。GBK:中国的中文编码表升级。最多两个字节编码Unicode:国际标准码,融合了目前人类使用的所有字符。所有的文字都用两个字节来表示。UTF-8:变长的编码方式,可用1-4个字节来表示一个字符。
11.6 标准输入输出流
默认输入设备是:键盘,输出设备是:显示器。 System.in的类型是InputStream,System.out的类型是PrintStream。
重定向:通过System类的setIn,setOut方法对默认设备进行改变。
// 例题:从键盘输入字符串,将读取到的字符串转成大写输出。然后继续进行输入操作,直至输入“e”或“exit”时,退出程序// 把"标准"输入流(键盘输入)这个字节流包装成字符流,再包装成缓冲流BufferedReader br = new BufferedReader(new InputStreamReader(System.in));String s = null;try {while ((s = br.readLine()) != null) { // 读取用户输入的一行数据 --> 阻塞程序if ("e".equalsIgnoreCase(s) || "exit".equalsIgnoreCase(s)) {System.out.println("安全退出!!");break;}// 将读取到的整行字符串转成大写输出System.out.println("-->:" + s.toUpperCase());System.out.println("继续输入信息");} catch (IOException e) {e.printStackTrace();} finally {try {if (br != null) {br.close(); // 关闭过滤流时,会自动关闭它包装的底层节点流}} catch (IOException e) {e.printStackTrace();}}
11.7 对象流
可以把对象写入到数据源中,也能把对象从数据源中还原回来。ObjectOutputStream和ObjectInputStream不能序列化static(不属于对象,属于类)和transient修饰的成员变量。
对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可序列化的,该类必须实现Serializable或 Externalizable接口。
凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量: serialVersionUID; 这个变量表明类的不同版本间的兼容性。如果类没有显示定义这个静态常量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量(即非静态成员变量)做了修改,serialVersionUID 可能发生变化。故建议,显式声明。
使用对象流序列化对象:1.创建一个 ObjectOutputStream2.调用 ObjectOutputStream 对象的 writeObject(对象) 方法输出可序列化对象3.注意写出一次,操作flush()一次ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("data.txt"));Person p = new Person("韩梅梅", 18, "中华大街", new Pet());oos.writeObject(p);oos.flush();oos.close();反序列化:1.创建一个 ObjectInputStream2.调用 readObject() 方法读取流中的对象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("data.txt"));Person p1 = (Person)ois.readObject();ois.close();
11.8 随机存取文件流
RandomAccessFile 支持 “随机访问” ,可以直接跳到文件的任意地方来读、写文件。在写文件时,若文件不存在,将自动创建文件;若文件存在,则写入数据默认会从文件第一个数据开始依次进行数据覆盖,可通过seek方法修改覆盖起始位置。通过getFilePointer获取文件记录指针的当前位置;seek将文件记录指针定位到指定位置。
public RandomAccessFile(File file, String mode)public RandomAccessFile(String name, String mode)r: 以只读方式打开,该文件必须存在rw:以读写方式打开,文件不存在将自动创建rwd:以读写方式打开;同步文件内容的更新rws:以读写方式打开;同步文件内容和元数据的更新
在实现如下载功能时,若中途下载失败则仅能从头开始,而使用该类可实现多线程断点下载的功能,下载前建立两个临时文件,一个是与被下载文件大小相同的空文件,另一个是记录文件指针的位置文件,每次暂停时都保存指针。
// 实现在定点位置输入xyzRandomAccessFile raf = new RandomAccessFile("test.txt", "rw");raf.seek(5);//先读出来String temp = raf.readLine(); // 每次要将插入位置后的所有数据读出,效率较低,因此在实现时要规避插入,尽量使用追加操作raf.seek(5);raf.write("xyz".getBytes());raf.write(temp.getBytes());raf.close();
11.9 Scanner类
Scanner scan = new Scanner(System.in); // 从键盘接收数据if (scan.hasNext()) { // 判断是否还有输入String str1 = scan.next(); // 读取以空白符为结束符的字符串String str2 = scan.nextLine(); // 读取以回车为结束符的字符串}scan.close(); // 关闭流
scan.hasNextInt()scan.nextInt()scan.hasNextFloat()scan.nextFloat()scan.hasNextDouble()scan.nextDouble()
