Java--IO流
IO流
文章目录
- IO流
- 一、File类
- 二、IO流的原理及流的分类
-
- 1.Java IO原理
- 2.流的分类
-
- 2.1.根据流向分类
- 2.2.根据数据单位分类
- 2.3.根据流的角色分类
- 3.字符流
-
- 3.1.Reader 读入文件数据
- 3.2.Writer 写入数据到文件
- 3.3.注意事项
- 4.字节流
-
- 4.1.使用字节流复制图片文件
- 4.2.文件目录如下
- 5.缓冲流
-
- 5.1.BufferedInputStream && BufferedOutputStream
- 5.2.BufferedReader&& BufferedWriter
- 6.转换流(转换流提供了在字节流和字符流之间的转换)
- 7.其他的流的使用
-
- 7.1.标准的输入输出流
- 8.对象流
-
- 8.1.对象流的使用
- 8.2.对象的序列化
- 8.3.使用序列化跟反序列化读取和写入操作
- 9.RandomAccessFile
-
- 9.1.RandomAccessFile概述
- 9.2.不同构造器
一、File类
1.File的含义和位置
File类对象代表一个文件或者一个文件夹;File类存放在io包下。
2.获取File类的三种方式
public static void test1() { //1.通过相对路径或者绝对路径直接获取对应的file类 //File(String filePath) // 通过相对路径获取file类 内存层面的对象 File file1 = new File("first.txt"); System.out.println(file1); // 通过绝对路径获取file类 // File.separator 根据不同的系统区分 //路径分隔符 windows:\\ unix:/ File file2 = new File("D:" + File.separator + "myproject" + File.separator + "my-javabase-demo" + File.separator + "javase-demo" + File.separator + " first.txt"); System.out.println(file2); //2.父文件夹的方式跟子文件夹的方式获取file类 //File(String parentPath,String childPath) File file3 = new File("D:\\myproject\\my-javabase-demo", "javase-demo"); System.out.println(file3); //3.根据file对象,还有子文件夹获取对应的file类 //File(File parentFile,String childPath) File file4 = new File(file3, "first.txt"); System.out.println(file4); }
2.1.File类路径注意事项:
相对路径:相较于某个路径下,指明的路径。 idea @test的单元测试指在同一个module下,main方法里面指同一个工程下;
绝对路径:包含盘符在内的文件或文件目录的路径
3.File常见功能
目录结构
3.1.File类的获取功能
3.1.1.常见的File类获取功能
public static void test2() { /** * 通过相对路径跟绝对路径的获取查看区别 */ File file1 = new File("first.txt"); File file2 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\second.txt"); System.out.println(file1.getAbsolutePath()); System.out.println(file1.getPath()); System.out.println(file1.getParent()); System.out.println(file1.getName()); System.out.println(file1.length()); System.out.println(file1.lastModified()); System.out.println("----------"); System.out.println(file2.getAbsolutePath()); System.out.println(file2.getPath()); System.out.println(file2.getParent()); System.out.println(file2.getName()); System.out.println(file2.length()); System.out.println(file2.lastModified()); // getAbsolutePath 获取绝对路径。绝对路径和相对路径获取的file类结果相同 // getPath 获取路径。相对路径获取的file类:文件名;绝对路径获取的file类:全路径 // getParent 上级目录(没有为null)。相对路径获取的file类:null;绝对路径获取的file类:全路径 // getName 获取文件名。相同 // length 获取文件长度(即:字节数)。相对路径获取的file类:0;绝对路径获取的file类:对应长度 // lastModified 最后一次的修改时间戳。相对路径获取的file类:0;绝对路径获取的file类:对应时间 }
3.1.2.File对象获取对应的文件夹列表
public static void test3() { /** * 获取对应的文件夹列表,只能用绝对路径 */ File file = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\di"); //file.list() 获取指定目录下的所有文件或者文件目录的名称数组 for (String s : Objects.requireNonNull(file.list())) { System.out.println(s); } //file.listFiles() 获取指定目录下的所有文件或者文件目录的File数组 for (File listFile : Objects.requireNonNull(file.listFiles())) { System.out.println(listFile.getAbsolutePath()); } }
3.2.File类的重命名功能
public static void test4() { File file1 = new File("first.txt"); // 相对路径的无法进行 重命名 false System.out.println(file1.renameTo(new File("1.txt"))); File file2 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\second.txt"); // renameTo 里面的文件路径为外层文件夹下的路径,然后对应的文件会改名字且移动位置 System.out.println(file2.renameTo(new File("D:\\myproject\\my-javabase-demo\\javase-demo\\three.txt"))); }
3.3.File类的判断功能
public static void test5() { // 相对路径所有的判断功能都是false 需要用 绝对路径判断 File file1 = new File("first.txt"); File file2 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\three.txt"); System.out.println(file2.isDirectory());// 判断是否是文件目录 System.out.println(file2.isFile());// 判断是否是文件 System.out.println(file2.exists());// 判断是否存在 System.out.println(file2.canRead());// 判断是否可读 System.out.println(file2.canWrite());// 判断是否可写 System.out.println(file2.isHidden());// 判断是否隐藏 }
3.4.File类的创建功能
public static void test6() { File file1 = new File("di.txt"); File file2 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\four.txt"); File file3 = new File("di"); File file4 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\four"); try { // 创建文件。若文件存在,则不创建,返回false // 相对路径创建为大文件夹下面 System.out.println(file1.createNewFile()); System.out.println(file2.createNewFile()); // 创建文件目录。如果上层文件目录不存在,一并创建 System.out.println(file3.mkdir()); System.out.println(file4.mkdir()); } catch (IOException e) { e.printStackTrace(); } }
3.5.File类的删除功能
public static void test7() { // 相对路径无法删除 File file1 = new File("first.txt"); System.out.println(file1.delete()); // 绝对路径删除 File file2 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\first.txt"); System.out.println(file2.delete()); // 文件夹删除如果里面包含文件无法删除 // 需要删除里面的文件 然后删除对应的文件夹,即空文件夹才可以删除 File file3 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\di"); System.out.println(file3.delete()); if (file3.isDirectory()) { for (File file : file3.listFiles()) { file.delete(); } } System.out.println(file3.delete()); }
4.File类注意事项
当硬盘有一个真实的文件或目录存在时,创建File对象,各个属相会显示赋值;
当硬盘中没有真实的文件或者文件夹对应时,创建对象时,除了指定的目录和路径外,其他的属性取成员变量的默认值。
二、IO流的原理及流的分类
1.Java IO原理
- I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。
- Java程序中,对于数据的输入/输出操作以“流(stream)” 的方式进行。
- java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
2.流的分类
2.1.根据流向分类
- 输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
- 输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。
2.2.根据数据单位分类
- 字节流(8 bit)
- 字符流(16 bit)
2.3.根据流的角色分类
- 节点流 (直接从数据源或目的地读写数据),直接作用在源文件上面的。
- 处理流 (不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。作用在已有的流之上)
3.字符流
3.1.Reader 读入文件数据
// read()方法的操作 public static void test1() { // 1.实例化file类的对象,指明要操纵的文件 File file = new File("javase-demo\\three.txt"); FileReader fileReader = null; try { // 2.提供具体的流 fileReader = new FileReader(file); // 3.数据读入 // read():返回读入的字符,如果达到文件的末尾,返回-1 // 读入的文件一定要存在,否则FileNotFoundException。 int data = fileReader.read(); // 循环的遍历文件里面的字符 while (data != -1) { System.out.println((char) data); data = fileReader.read(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // 4.关闭流 try { if (fileReader != null) { fileReader.close(); } } catch (IOException e) { e.printStackTrace(); } } }
// read(char[] cArr) public static void test2() { FileReader fileReader = null; try { // 1.File类的实例化 File file = new File("javase-demo\\three.txt"); // 2.FileReader流的实例化 fileReader = new FileReader(file); // 3.读入的操作 char[] cArr = new char[5]; int len; while ((len = fileReader.read(cArr)) != -1) { // 如果用此方式会导致每次的数据覆盖原本的char数组,如果此次的char数组没有读满,会将上一次读入的也再次读取; // for (int i = 0; i < cArr.length; i++) // { // System.out.println(cArr[i]); // } // 每次只遍历读取的长度 // for (int i = 0; i < len; i++) // { // System.out.print(cArr[i]); // } // 通过string的截取读取 System.out.print(new String(cArr, 0, len)); } } catch (IOException e) { e.printStackTrace(); } finally { // 4.流资源关闭 if (fileReader != null) { try { fileReader.close(); } catch (IOException e) { e.printStackTrace(); } } } }
3.2.Writer 写入数据到文件
public static void test3() { FileWriter fileWriter = null; try { // 1.File类的实例化,指明写出的文件 File file = new File("javase-demo\\one.txt"); // 2.提供FileWriter对象,用于数据的写出 // File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。 // 如果流使用的构造器是:FileWriter(file,false) / FileWriter(file):对原有文件的覆盖 // 如果流使用的构造器是:FileWriter(file,true):不会对原有文件覆盖,而是在原有文件基础上追加内容 fileWriter = new FileWriter(file, true); // 3.写出的操作 fileWriter.write("小白,你好\n"); fileWriter.write("小白,加油\n"); } catch (IOException e) { e.printStackTrace(); } finally { // 4.流的关闭 try { if (fileWriter != null) { fileWriter.close(); } } catch (IOException e) { e.printStackTrace(); } } }
public static void test4() { // 将文件读入并写出,即复制文件 FileReader fileReader = null; FileWriter fileWriter = null; try { // 1.创建File类的对象,指明读入和写出的文件 File file1 = new File("javase-demo\\one.txt"); File file2 = new File("javase-demo\\two.txt"); // 2.提供FileWriter,FileReader对象,用于数据的读入和写出 fileReader = new FileReader(file1); fileWriter = new FileWriter(file2); // 3.读取数据和写入数据的操作 // 方式一:每次一个一个的写出 // int data; // while ((data = fileReader.read()) != -1) // { // fileWriter.write(data); // } // 方式二:批量的写出 char[] cArr = new char[5]; int len;// 记录每次读入到cbuf数组中的字符的个数 while ((len = fileReader.read(cArr)) != -1) { // 每次写出len个字符 fileWriter.write(cArr, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { try { // 4.流资源的关闭 if (fileReader != null) { fileReader.close(); } if (fileWriter != null) { fileWriter.close(); } } catch (IOException e) { e.printStackTrace(); } } }
3.3.注意事项
- 字符流无法处理图片之类格式的文件
- 对于文本文件(.txt,.java,.c,.cpp …),使用字符流处理
- 对于非文本文件(.jpg,.mp3,.doc,.ppt,.xls),使用字节流处理
- 使用字节流处理文本文件,如果遇到中文等,可能出现乱码。
- 如果是单纯的复制文件,则字节流和字符流都可以使用。
4.字节流
4.1.使用字节流复制图片文件
public static void test2() { // 使用字节流复制图片文件 FileInputStream inputStream = null; FileOutputStream outputStream = null; try { // 1.实例化 file File fileScr = new File("javase-demo\\img.png"); File fileDest = new File("javase-demo\\img1.png"); // 2.创建流 inputStream = new FileInputStream(fileScr); outputStream = new FileOutputStream(fileDest); // 3.数据操作 int data; while ((data = inputStream.read()) != -1) { outputStream.write(data); } } catch (IOException e) { e.printStackTrace(); } finally { // 4.关闭流资源 try { if (inputStream != null) inputStream.close(); if (outputStream != null) outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
4.2.文件目录如下
5.缓冲流
5.1.BufferedInputStream && BufferedOutputStream
public static void test1() { // 利用缓冲流实现非文本文件的复制 long start = System.currentTimeMillis(); FileInputStream inputStream = null; FileOutputStream outputStream = null; BufferedInputStream bufferedInputStream = null; BufferedOutputStream bufferedOutputStream = null; try { // 1.实例化file对象 File file1 = new File("javase-demo\\img.png"); File file2 = new File("D:\\img.png"); // 2.创建流对象 // 2.1.节点流 inputStream = new FileInputStream(file1); outputStream = new FileOutputStream(file2); // 2.2.缓冲流 bufferedInputStream = new BufferedInputStream(inputStream); bufferedOutputStream = new BufferedOutputStream(outputStream); // 3.文件操作,复制 byte[] bytes = new byte[1024]; int len; while ((len = bufferedInputStream.read(bytes)) != -1) { bufferedOutputStream.write(bytes, 0, len); //刷新缓冲区// bufferedOutputStream.flush(); } } catch (IOException e) { e.printStackTrace(); } finally { // 4.关闭流资源, // 由于包装了缓冲流,有一个关闭顺序,即先关闭缓冲流(外层),再关闭节点流(内层) try { if (bufferedInputStream != null) bufferedInputStream.close(); if (bufferedOutputStream != null) bufferedOutputStream.close(); // 关闭外层流的同时,内层的流也一同关闭,可不用关闭 if (inputStream != null) inputStream.close(); if (outputStream != null) outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } long end = System.currentTimeMillis(); System.out.println(end - start); }
5.2.BufferedReader&& BufferedWriter
public static void test2() { // 使用BufferedReader和BufferedWriter实现文本文件的复制 long start = System.currentTimeMillis(); BufferedWriter bufferedWriter = null; BufferedReader bufferedReader = null; try { // 1.实例化file对象 File file1 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\text.txt"); File file2 = new File("D:\\text.txt"); // 2.创建流对象 // 2.1.节点流 字符流 FileReader fileReader = new FileReader(file1); FileWriter fileWriter = new FileWriter(file2); // 2.2.缓冲流 bufferedReader = new BufferedReader(fileReader); bufferedWriter = new BufferedWriter(fileWriter); // 3.文件操作,复制 // 方式一:使用char[]数组// char[] cbuf = new char[1024];// int len;// while ((len = bufferedReader.read(cbuf)) != -1)// {// bufferedWriter.write(cbuf, 0, len);// // bw.flush();// } //方式二:使用String String data; while((data = bufferedReader.readLine()) != null){ //方法一:// bw.write(data + "\n");//data中不包含换行符 //方法二: bufferedWriter.write(data);//data中不包含换行符 bufferedWriter.newLine();//提供换行的操作 } } catch (IOException e) { e.printStackTrace(); } finally { try { // 4.关闭流 if (bufferedReader != null) bufferedReader.close(); if (bufferedWriter != null) bufferedWriter.close(); } catch (IOException e) { e.printStackTrace(); } } long end = System.currentTimeMillis(); System.out.println(end - start); }
6.转换流(转换流提供了在字节流和字符流之间的转换)
7.其他的流的使用
7.1.标准的输入输出流
//利用标准输入输出流,从控制台输入 字母转换成大写, //输入e 或者 exit 结束 public static void test1() { BufferedReader bufferedReader = null; try { InputStreamReader inputStreamReader = new InputStreamReader(System.in); bufferedReader = new BufferedReader(inputStreamReader); String data; while (true) { System.out.println("输入字符串:"); data = bufferedReader.readLine(); if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)) { System.out.println("程序结束"); break; } String upperCase = data.toUpperCase(); System.out.println(upperCase); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (bufferedReader != null) { bufferedReader.close(); } } catch (IOException e) { e.printStackTrace(); } } }
8.对象流
8.1.对象流的使用
- ObjectInputStream && OjbectOutputSteam
用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。 - 序列化:用ObjectOutputStream类保存基本类型数据或对象的机制
- 反序列化:用ObjectInputStream类读取基本类型数据或对象的机制
- ObjectInputStream || OjbectOutputSteam 不能序列化static和transient修饰的成员变量
8.2.对象的序列化
对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点(序列化)。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象(反序列化)。
8.3.使用序列化跟反序列化读取和写入操作
public static void test1() { // 序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去 // 使用ObjectOutputStream实现 ObjectOutputStream outputStream = null; try { outputStream = new ObjectOutputStream(new FileOutputStream("javase-demo\\object.txt")); outputStream.writeObject(new String("你好吗,小朋友")); outputStream.flush();// 刷新操作 outputStream.writeObject(new Employee("小白", 1)); outputStream.flush(); outputStream.writeObject(new Employee("小红", 23, 1001, new Account(5000))); outputStream.flush(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (outputStream != null) { outputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } }
public static void test2() { // 反序列化:将磁盘文件中的对象还原为内存中的一个java对象 // 使用ObjectInputStream来实现 ObjectInputStream objectInputStream = null; try { objectInputStream = new ObjectInputStream(new FileInputStream("javase-demo\\object.txt")); Object obj = objectInputStream.readObject(); String str = (String) obj; Employee e1 = (Employee) objectInputStream.readObject(); Employee e2 = (Employee) objectInputStream.readObject(); System.out.println(str); System.out.println(e1); System.out.println(e2); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { try { if (objectInputStream != null) { objectInputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } }
public class Employee implements Serializable{ public static final long serialVersionUID = 475461233534532L; private String name; private int age; private int id; private Account acct; public Employee(String name, int age, int id) { this.name = name; this.age = age; this.id = id; } public Employee(String name, int age, int id, Account acct) { this.name = name; this.age = age; this.id = id; this.acct = acct; } @Override public String toString() { return "Employee{" + "name='" + name + '\'' + ", age=" + age + ", id=" + id + ", acct=" + acct + '}'; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Employee(String name, int age) { this.name = name; this.age = age; } public Employee() { }}
public class Account implements Serializable{ public static final long serialVersionUID = 4713454534532L; private double balance; @Override public String toString() { return "Account{" + "balance=" + balance + '}'; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public Account(double balance) { this.balance = balance; }}
9.RandomAccessFile
9.1.RandomAccessFile概述
- RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口
- RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
- 如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。
- 可以通过相关的操作,实现RandomAccessFile“插入”数据的效果
9.2.不同构造器
- public RandomAccessFile(File file, String mode)
- public RandomAccessFile(String name, String mode)
创建 RandomAccessFile 类实例需要指定一个 mode 参数,该参数指定 RandomAccessFile 的访问模式: - r: 以只读方式打开
- rw:打开以便读取和写入
- rwd:打开以便读取和写入;同步文件内容的更新
- rws:打开以便读取和写入;同步文件内容和元数据的更新
- 如果模式为只读r。则不会创建文件,而是会去读取一个已经存在的文件,
如果读取的文件不存在则会出现异常。 如果模式为rw读写。如果文件不存在则会去创建文件,如果存在则不会创建。