zoukankan      html  css  js  c++  java
  • Java基础-day19

    Java 提供了许多实现文件输入 / 输出的类。 这些类可以分为文本 I/O 类二进制 I/O 类

    在Java中如何处理文本I/O

    使用Scanner类读取文本数据,使用PrintWriter类写文本数据

    为了将文本写入一个名为temp.txt的文件中,可以使用PrintWriter类创建一个对象:

    PrintWriter output = new PrintWriter("temp.txt");
    

    可以调用该对象的print方法向文件写入一个字符串

    output.print("Java 101");
    

    之后关闭文件

    output.close();
    

    从文件temp.txt中读入数据:

    Scanner input = new Scanner(new File("temp.txt"));
    System.out.println(input.nextLine());
    

    Snipaste_2020-05-04_20-04-53

    文本I/O 与 二进制I/O

    二进制 I / O 不涉及编码和解码 , 因此比文本 I / O 更加高效

    Snipaste_2020-05-04_20-14-06

    为了保持一致性,使用扩展名.txt来命名文本文件,使用.dat来命名二进制文件

    二进制I/O类

    抽象类 InputStream 是读取二进制数据的根类 , 抽象类 OutputStream 是写入二进制数据的根类

    Snipaste_2020-05-04_20-17-31

    Snipaste_2020-05-04_20-22-35

    **二进制 I / O 类 中 的 所 有 方 法 都 声 明 为 抛 出java.io.IOException java.io. IOException的子类 **

    FileInputStream FileOutputStream

    FileInputStream : 从文件读取字节

    FileOutputStream :向文件写入字节

    1. 构造一个FileInputStream对象
    Snipaste_2020-05-04_20-31-18

    如果试图为一个不存在的文件创建 FilelnputStream 对象 , 将会发生java.io.FileNotFoundException 异常

    1. 构造一个FileOutputStream对象
    Snipaste_2020-05-04_20-33-41
    • 如果这个文件不存在 , 就会创建一个新文件 。 如果这个文件已经存在 , 前两个构造方法将会删除文件的当前内容 。 为了既保留文件现有的内容又可以给文件追加新数据 , 将最后两个构造方法中的参数 append 设置为 true 。

    • 几乎所有的I/O类中的方法都会抛出异常java.io.IOException

    使用二进制 I / O 将从 1 到 10 的 10 个字节值写入一个名为 temp . dat 的文件 , 再把它们从文件中读出来

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class TestFileStream {
        public static void main(String[] args) throws IOException {
            try(            // 利用try-with-resources来声明和创建输入流
                FileOutputStream output = new FileOutputStream("temp.dat");
                    ){
                for (int i = 1; i <= 10; i++)
                    output.write(i);    // 也可以写成 output.write((byte)i)
            }
    
            try(            // 利用try-with-resources来声明和创建输出流
                    FileInputStream input = new FileInputStream("temp.dat");
                    ){
                int value;
                while((value = input.read()) != -1) // -1意味着文件结束
                    System.out.print(value + " ");
            }
        }
    }
    
    1 2 3 4 5 6 7 8 9 10
    

    java.io.InputStreamjava.io.OutputStream实现了AutoClosable接口,该接口中定义了close()方法,用于关闭资源。任何AutoClosable类型的对象可以用于try-with-resources语法中实现自动关闭。

    FileInputStream类的实例可以作为参数去构造一个Scanner对象,而FileOutputStream类的实例可以作为参数构造一个PrinterWriter对象

    new PrintWriter(new FileOutputStream("temp.txt", true));
    

    FilterInputStreamFilterOutputStream

    Snipaste_2020-05-04_20-59-58

    DataInputStreamDataOutputStream

    DataInputStream从数据流读取字节,并且将他们转换为合适的基本类型值或字符串

    DataOutputStream将基本类型的值或字符串转换为字节,并且将字节输出到数据流

    Snipaste_2020-05-04_21-59-51Snipaste_2020-05-04_21-59-57

    Snipaste_2020-05-04_21-59-57

    二进制I/O中的字符与字符串

    — 个统一码由两个字节构成。

    1. writeChar(char c)方法将字符c的统一码写入输出流
    2. writeChars(String s)方法将字符串s中所有字符的统一码写到输出流中
    3. writeBytes(String s)方法将字符串s中每个字符统一码的低字节写到输出流,统一码的高字节被丢弃,该方法适用于由ASCII码字符构成的字符串(因为ASCII码仅仅存储统一码的低字节)
      • 如果一个字符串包含非ASCII码的字符,必须使用writeChars方法实现写入这个字符串
    4. writeUTF(String s)方法将两个字节的长度信息写入输出流,后面紧跟的是字符串s中每个字符的改进版UTF-8的形式
      • readUTF()方法读取一个使用writeUTF方法写入的字符串
      • UTF-8格式具有存储每个ASCII码就节省一个字节的优势

    writeUTF("ABCDEF")写入文件的8个字节(00 06 41 42 43 44 45 46),头两个字节存储的是字符串中的字符个数

    创建DataInputStream类和DataOutputStream

    根据上面的UML图,通过下面构造方法来创建DataInputStream类和DataOutputStream

    public DataInputStream(InputStream instream);
    public DataOutputStream(OutputStream outStream);
    
    DataInputStream input = new DataInputStream(new FileInputStream("in.dat")); // 为文件in.dat创建一个输入流
    DataOutputStream output = new DataOutputStream(new FileOutputStream("out.dat"));	// 为文件out.dat创建一个输出流
    

    例子:将学生的名字和分数写入名为temp.dat的文件中

    import java.io.*;
    
    public class TestDataStream {
        public static void main (String[] args) throws IOException {
            try (
                    DataOutputStream output = 
                new DataOutputStream(new FileOutputStream("temps.dat"));
            ){
                output.writeUTF("yzy");
                output.writeDouble(89.0);
                output.writeUTF("wjy");
                output.writeDouble(90.2);
            }
    
            try(
                    DataInputStream input = 
                new DataInputStream(new FileInputStream("temps.dat"));
             ){
                for (int i = 1; i <= 2; i++)
                    System.out.println(input.readUTF() + " " + input.readDouble());
            }
        }
    }
    
    yzy 89.0
    wjy 90.2
    
    Snipaste_2020-05-05_09-34-34

    检测文件的末尾

    如果到达InputStream 的末尾之后还继续从中读取数据 , 就会发生 EOFException 异常 。
    这个异常可以用来检査是否已经到达文件末尾

    import java.io.*;
    
    public class TestEOF {
        public static void main(String[] args) throws IOException {
            try {
                try (
                        DataOutputStream output =
                                new DataOutputStream(new FileOutputStream("testEOF.dat"));
                ) {
                    output.writeDouble(1.1);
                    output.writeDouble(2.2);
                    output.writeDouble(3.3);
                }
    
                try(
                        DataInputStream input =
                                new DataInputStream(new FileInputStream("testEOF.dat"));
                        ){
                    while(true){
                        System.out.println(input.readDouble());
                    }
                }
            }
            catch (EOFException ex){
                System.out.println("All data were read");
            }
            catch (IOException ex){
                ex.printStackTrace();
            }
        }
    }
    
    1.1
    2.2
    3.3
    All data were read
    

    BufferedInputStreamBufferedOutputStream

    这两个类可以通过减少磁盘读写次数来提高输入和输出速度

    Snipaste_2020-05-05_09-42-59

    这两个类没有包含新的方法,所有方法继承自InputStream类和OutputStream

    Snipaste_2020-05-05_09-46-58

    Snipaste_2020-05-05_09-47-07

    如果没有指定缓冲区大小 , 默认的大小是 512 个字节

    DataOutputStream output = new DataOutputStream(
    	new BufferedOutputStream(new FileOutputStream("temp.dat")));
    
    DataInputStream input = new DataInputStream(
        new BufferedInputStream(new FileInputStream("temp.dat")));
    

    实例学习:复制文件

    import java.io.*;
    
    public class Copy {
        public static void main(String[] args) throws IOException {
            if (args.length != 2){
                System.out.println(" Usage : java Copy sourceFile targetfile");
                System.exit(1);
            }
    
            File sourceFile = new File(args[0]);
            if (!sourceFile.exists()){
                System.out.println("sourceFile does not exist");
                System.exit(2);
            }
    
            File targetFile = new File(args[1]);
            if (targetFile.exists()){
                System.out.println("targetFile already exist");
                System.exit(3);
            }
    
            try(
                    BufferedInputStream input = new BufferedInputStream(
                            new FileInputStream(sourceFile));
                    BufferedOutputStream output = new BufferedOutputStream(
                            new FileOutputStream(targetFile));
                    ){
                int r, numberOfByteCopied = 0;
                while ((r = input.read()) != -1){
                    output.write((byte)r);
                    numberOfByteCopied++;
                }
                System.out.println("number of copied : " + numberOfByteCopied);
            }
    
        }
    }
    
    D:JAVA_IDEAJavaProjectsChapter05src>java Copy testCopy.txt target.txt
    number of copied : 23
    
    Snipaste_2020-05-05_10-39-08

    对象I/O

    ObjectInputStream类和ObjectOutputStream类可以用于读/写可序列化的对象,也可以实现基本数据类型与字符串的输人和输出,包含了DataInputStream类和DataOutputStream类的所有功能

    Snipaste_2020-05-05_10-45-18

    public ObjectInputStream(InputStream in)	// 创建一个对象输入流
    public ObjectOutputStream(OutputStream out) // 创建一个对象输出流
    
    1. 姓名 、 分数和当前日期写入名为 object.dat 的文件
    import java.io.*;
    public class TestObjectOutputStream{
        public static void main(String[] args) throws IOException{
            try(
                ObjectOutputStream output = 
                    new ObjectOutputStream(new FileOutputStream("object.dat"));
            ){
                output.writeUTF("John");
                output.writeDouble(33.3);
                outout.writeObject(new java.util.Date());	// 将对象写入文件
            }
        }
    }
    

    可以添加缓冲区:

    ObjectOutputStream output = new ObjectOutputStream(
    new BufferedOutputStream(new FileOutputStream("object.dat")));
    
    1. 读回这些对象:按照写入时的类型和顺序。为了得到所需的类型 , 必须使用 Java 安全的类型转换
    import java.io.*;
    public class TestObjectOUtputStream{
        public static void main(String[] args)
        throws ClassNotFoundException, IOException{
            try(
                ObjectInputStream input = 
                new ObjectInputStream(new FileInputStream("object.dat"));
            ){
                String name = input.readUTF();
                double score = input.readDouble();
                java.util.Date date = (java.util.Date)(input.readObject());
                // readObject()方法可能会拋出异常java.lang.ClassNotFoundException
                // readObject()读入的是Object对象,所以应将他转换为Date类型
                System.out.println(name + " " + score + " " + date);
            }
        }
    }
    

    Serializable接口

    Snipaste_2020-05-05_11-15-41

    Snipaste_2020-05-05_11-16-42

    序列化数组

    如果数组中的所有元素都是可序列化的 , 这个数组就是可序列化的 。 一个完整的数组可以用 writeObject 方法存入文件 , 随后用 readObject 方法恢复

    import java.io.*;
    
    public class TestObjectStreamWithArray {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            int[] num = {1, 2, 3, 4, 5};
            String[] str = {"shang", "shan", "da", "lao", "hu"};
    
            try (
                    ObjectOutputStream output =
                            new ObjectOutputStream(new FileOutputStream("testOb.dat", true));
                    ){
                output.writeObject(num);
                output.writeObject(str);
            }
    
            try (
                    ObjectInputStream input =
                            new ObjectInputStream(new FileInputStream("testOb.dat"));
                    ){
                int[] number = (int[])(input.readObject());
                String[] strings = (String[])(input.readObject());
    
                for (int i = 0; i < number.length; i++){
                    System.out.print(number[i] + " ");
                }
                System.out.println();
    
                for (int i = 0; i < strings.length; i++){
                    System.out.print(strings[i] + " ");
                }
            }
        }
    }
    
    1 2 3 4 5 
    shang shan da lao hu 
    

    随机访问文件

    Java 提供了RandomAccessFile类 , 允许从文件的任何位置进行数据的读写

    1. 上面学习的都是只读的和只写的,这称为顺序流, 使用顺序流打开的文件称为**顺序访问文件 **。 顺序访问文件的内容不能更新 。

    2. Java 提供了RandomAccessFile类 , 允许在文件的任意位置上进行读写 。 使用 RandomAccessFile 类打开的文件称为随机访问文件

    Snipaste_2020-05-05_11-36-05

    RandomAccessFile raf = new RandomAccessFile("test.dat", "rw"); 	// rw为可读写的
    
    • 如果文件 test.dat 已经存在 , 则创建raf以便访问这个文件
    • 如果test.dat不存在,则创建一个名为 test.dat 的新文件,再创建 raf 来访问这个新文件

    随机访问文件是由字节序列组成的。一个称为文件指针 的特殊标记定位这些字节中的某个字节的位置

    Snipaste_2020-05-05_11-40-52
    import java.io.*;
    
    public class TestRandomAccessFile {
        public static void main(String[] args) throws IOException {
            try(
               RandomAccessFile inout = new RandomAccessFile("inout.dat", "rw");
            ){
                inout.setLength(0); // 清空文件
                for (int i = 0; i < 200; i++){  // 写入200个数字
                    inout.writeInt(i);
                }
    
                System.out.println("目前文件长度为:" + inout.length());
    
                inout.seek(0);  // 将文件指针移动到头位置
                System.out.println("第一个数:" + inout.readInt());
    
                inout.seek(9 * 4);  // 将文件指针移到第10个数位置
                System.out.println("第10个数:" + inout.readInt());
    
                inout.seek(inout.length()); // 将文件指针移动末尾
                inout.writeInt(999);
    
                System.out.println("现在文件长度为:" + inout.length());
            }
        }
    }
    
    目前文件长度为:800
    第一个数:0
    第10个数:9
    现在文件长度为:804
    

    Write by Gqq

  • 相关阅读:
    JAVA基础——编程练习(二)
    JAVA基础——面向对象三大特性:封装、继承、多态
    JVM内存
    50. Pow(x, n) (JAVA)
    47. Permutations II (JAVA)
    46. Permutations (JAVA)
    45. Jump Game II (JAVA)
    43. Multiply Strings (JAVA)
    42. Trapping Rain Water (JAVA)
    41. First Missing Positive (JAVA)
  • 原文地址:https://www.cnblogs.com/zgqcn/p/12830090.html
Copyright © 2011-2022 走看看