Java笔记:IO流
1. IO流理解
IO流中的I是单词Input的缩写,表示输入或者读(Read),O是单词Output的缩写,表示输出或写(Write),输入输出或者读写都是相对于内存而言的,输入即从硬盘中读取数据到内存中,输出即将内存中的数据写入到硬盘。IO流就是输入和输出时的数据流(内存和硬盘之间的管道),IO的输入或输出也可以看做是文件的读和写,因为硬盘中的数据其实都是以文件的形式存储的,在硬盘上对文件的读写操作就对应了内存中对数据的输入和输出操作。
2. 流的读取方式
3. File类
“java.io.File”类和文件流的操作没有关系,也就是不能对文件进行读和写,File类是文件和目录路径名的一种抽象表示形式,即一个文件是File对象,一个目录也是File对象,它的构造方法中只需要传入一个文件或目录的路径名即可,注意,对于路径分隔符,Windows和Linux使用的分别是“\”和“/”,但是File中传入的路径可以统一使用“/”,在Windows中也可以识别。
File中的常用方法:
-
-
boolean createNewFile():如果File对象不存在,则将File对象创建为一个新的文件,如果存在则不能创建。
-
boolean mkdir():如果File对象不存在,则将File对象创建为一个新的目录。注意,此方法只能创建单个目录,不能递归创建目录。
-
boolean mkdirs():如果File对象不存在,则将File对象以递归方式创建目录。
-
String getParent():获取File对象的父路径(上一级路径)。
-
File getParentFile():返回File对象的父路径的File对象。
-
String getAbsolutePath():返回File对象的绝对路径。
-
boolean delete():删除File对象表示的文件或目录。
-
String getName():获取File对象的文件名或目录名。
-
boolean isFile():判断File对象是否是一个文件。
-
boolean isDirectory():判断File对象是否是一个目录。
-
long lastModified():返回File对象最后一次修改的时间的总毫秒数(从1970年1月1日开始)。
-
long length():返回File对象的总字节数。
-
boolean renameTo(File dest):File对象重命名。
-
获取一个文件及文件路径的通用方式:
// 返回文件的绝对路径 String path = Thread.currentThread().getContextClassLoader().getResource("myfile.txt").getPath(); // 返回文件对应的流 InputStream reader = Thread.currentThread().getContextClassLoader().getResourceAsStream("myfile.txt");
注:这种方式能获取到一个文件的绝对路径或文件流,但是需要注意,使用这种方式的前提是这个文件是在类路径下,IDEA工具的目录结构中就是在“[module_name]/src”路径下,即getResource中的参数是一个src文件夹下的相对路径。
4. Java中的IO流
使用示例:
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class FileInputStreamTest { public static void main(String[] args) { FileInputStream fis = null; try{ // FileInputStream中抛出了一个FileNotFoundException异常,即编译时异常 // 需要程序员手动处理,这里加一个try进行捕获 // input.txt文件中只有一行数据:helloworld fis = new FileInputStream("Z:\\Study\\Java\\input.txt"); /* // 以下read()只是演示,实际并不常用 // 打印结果为: // 104 // 101 // 108 // 108 // 111 // 119 // 111 // 114 // 108 // 100 int byteData = 0; while ((byteData = fis.read()) != -1) { System.out.println(byteData); } */ // 以下使用read(byte[] b)方法读取文件内容 byte[] bytes = new byte[6]; int count = fis.read(bytes); System.out.println(count); // 6 System.out.println(new String(bytes)); // hellow System.out.println(new String(bytes, 0, count)); // hellow count = fis.read(bytes); System.out.println(count); // 4 System.out.println(new String(bytes)); // orldow System.out.println(new String(bytes, 0, count)); // orld count = fis.read(bytes); System.out.println(count); // -1 System.out.println(new String(bytes)); // orldow } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (fis != null) { try { // close方法也是抛出了一个IOException异常的编译时异常,同样加一个try进行捕获 fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
FileOutpuStream
将字节内容写入到文件中,构造方法中同样可以传入一个文件路径或者表示文件的File对象,同时还可以指定第二参数为true。当只传入一个文件路径或File对象,如果文件已存在,会清空文件内容,如果文件不存在,则会自动创建该文件;也可以指定第二个参数为true,表示如果文件已存在则不会清空文件,而是会往文件末尾追加数据。常用的方法有:
使用示例:
import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class FileOutputStreamTest { public static void main(String[] args) { FileOutputStream fos = null; try { // 只传入一个文件路径:如果文件已存在,会清空文件内容,如果文件不存在,则会自动创建该文件 // fos = new FileOutputStream("Z:\\Study\\Java\\output.txt"); // 第二个参数表示如果文件已存在则不会清空文件,而是会往文件末尾追加数据 fos = new FileOutputStream("Z:\\Study\\Java\\output.txt", true); byte[] bytes = {97, 98, 99, 100}; // 将bytes数组全部写到文件中 fos.write(bytes); // 将bytes数组的一部分写到文件中 fos.write(bytes, 0, 2); // 将字符串输出到文件中 String s = "你好,世界"; byte[] bs = s.getBytes(); fos.write(bs); // 文件输出完成后,一定记得刷新一下 fos.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (fos != null) { try { // 文件操作完成后一定记得调用close()方法 fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
FileReader:和FileInputStream相比,在使用上都是类似的,只是需要把byte数组换成char数组即可。
FileWriter:和FileOutpuStream相比,在使用上也都是类似的,只是要把byte数组换成char数组,另外,由于字符串的特殊性,FileWriter的write方法还可以直接写入一个字符串到文件。
6. 缓冲流
缓冲流表示带有缓冲区的字节流或字符流,特点是使用这些流的时候不需要自定义byte数组或char数组。
包装流和节点流:缓冲流的使用涉及到一些概念,当一个流的构造方法中需要另一个流的时候,被传入的这个流称为节点流,外部负责包装这个节点流的流称为包装流或处理流。关闭包装流的时候也是只需要调用最外层包装流的close()方法即可,里面的节点流会自动关闭。同样,对于输出的流,也是只需要调用最外层包装流的flush()方法即可。
BufferedInputStream:是一个包装流,构造方法中需要传入一个InputStream类型(字节类型)的节点流。
BufferedOutputStream:是一个包装流,构造方法中需要传入一个OutputStream类型(字节类型)的节点流。
import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class BufferedReaderTest { public static void main(String[] args) { BufferedReader br = null; try { // 这里reader就是一个节点流,br就是一个包装流或处理流 // 文件内容只有一行:helloworld FileReader reader = new FileReader("Z:\\Study\\Java\\input.txt"); br = new BufferedReader(reader); // 读取一行数据,注意返回的数据是不包含末尾的换行符的 String line = br.readLine(); System.out.println(line); // helloworld // 读取到文件末尾,返回null line = br.readLine(); System.out.println(line); // null } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // 对于包装流来说,只需要调用最外层包装流的close()方法即可,里面的节点流会自动关闭。 if (br != null) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
PrintStream out = new PrintStream(new FileOutputStreasm("log.txt", true)); System.setOut(out);
// 实现Serializable,但这个接口没有任何方法需要去重写 public class User implements Serializable { private int id; private String name; ... }
序列化单个java对象
User u = new User(123, "zhangsan"); // 将user对象序列化到Z:\\userinfo文件中 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Z:\\userinfo")); oos.writeObject(s); oos.flush(); oos.close();
序列化多个java对象
// 这里使用ArrayList存放多个User对象 List<User> userList = new ArrayList<>(); userList.add(new User(111, "zhangyi")); userList.add(new User(222, "zhanger")); userList.add(new User(333, "zhangsan")); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Z:\\userinfo")); oos.writeObject(userList); oos.flush(); oos.close();
反序列化java对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Z:\\userinfo")); // 反序列化出来的对象需要进行强制类型转换一下 List<User> userList = (List<User>)ois.readObject(); ois.close();
username=root
password=123456
FileReader reader = new FileReader("user-conf.properties"); Properties pro = new Properties(); pro.load(reader); String username = pro.getProperty("username"); System.out.println(username); // root
资源绑定器:对于上面示例中的这类配置文件,相较于使用Properties对象来读取,更常用的方法是使用资源绑定器,具体使用示例如下:
// 资源绑定器,在java.util.ResourceBundle下,并且只能绑定xxx.properties文件 // 这个文件必须在类路径下(IDEA工具的结构中就是module下的src目录),而且参数传入时也不能加文件后缀“.properties”。 ResourceBundle bundle = ResourceBundle.getBundle("user-conf"); String value = bundle.getString("username");