读Java编程艺术之笔记(文件IO)(一)

数据流指具有一定字节长度和方向的线性有序的数据对象。

在Unix/Linux中,路径中的大、小写字母表示不同的路径;而Windows操作系统则忽略大小写。PS. File类的两个常量:File.separator在UNIX系统中值是/,在Windows系统中值是\\;File.pathSeparator在UNIX系统中值是:,在Windows系统中值是;。

Java流操作有关的类和接口:(这里的讨论转自他处,可惜笔记时未记出处)
    File类,对文件系统中文件及文件夹进行封装的对象。File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读。File类还拥有获取当前文件的路径名,判断指定文件是否存在,获得当前目录中的文件列表,创建、删除文件和目录的方法。
    RandomAccessFile类封装了字节流,同时也封装了一缓冲区(字符数组)通过内部的指针来操作字符数组中的数据,只操作文件。构造函数接收两种类型:文件路径(字符串形式)和File对象。进行RandomAccessFile对象实例化时,可指定操作模式(如r、rw),实例化时如果操作的文件不存在,会自动创建该文件;若文件存在,而写数据未指定位置,则会从头开始写,即覆盖原有的内容。
    字节流也称为原始数据,需要用户读入后做相应的转换,由InputStream、OutputStream及其子类处理;字符流的实现基于自动转换,读取数据时按照JVM默认编码自动转换成字符,由Writer、Reader及其子类处理。字节流与字符流的区别:读写单位不同,字节(Byte),字符(两字节的Unicode);处理对象不同,字节流可以处理所有数据类型(如图片等),读取的是机器存储时的字节,而字符流会由JVM将字节转化为Unicode字符,所以只能处理字符类型,对文本支持比较好。PS. InputStream,OutputStream,Reader,writer都是抽象类,所以不能直接new。

关于字节流与字符流区别的进一步讨论:详细出处参考http://blog.csdn.net/cynhafa/article/details/6882061
    字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件。通过两个例子来说明:
    使用字节流不关闭执行

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class OutputWriter {

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        // 第1步:使用File类找到一个文件
        File f = new File("d:" + File.separator + "test.txt"); // 声明File 对象
        // 第2步:通过子类实例化父类对象
        OutputStream out = null;
        // 准备好一个输出的对象
        out = new FileOutputStream(f);
        // 通过对象多态性进行实例化
        // 第3步:进行写操作
        String str = "Hello World!!!";
        // 准备一个字符串
        byte b[] = str.getBytes();
        // 字符串转byte数组
        out.write(b);
        // 将内容输出
        // 第4步:关闭输出流
        // out.close();
        // 此时没有关闭
    }
}

    此时test文件中有内容为Hello World!!!
    使用字符流不关闭执行

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class OutputWriter {

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        // 第1步:使用File类找到一个文件
        File f = new File("d:" + File.separator + "test.txt");// 声明File 对象
        // 第2步:通过子类实例化父类对象
        Writer out = null;
        // 准备好一个输出的对象
        out = new FileWriter(f);
        // 通过对象多态性进行实例化
        // 第3步:进行写操作
        String str = "Hello World!!!";
        // 准备一个字符串
        out.write(str);
        // 将内容输出
        // 第4步:关闭输出流
        // out.close();
        // 此时没有关闭
    }
}

    此时查看test文件,没有任何内容。
    字符流操作时使用了缓冲区,而在关闭字符流时会强制性地将缓冲区中的内容进行输出,但是如果程序没有关闭,程序中也没有关闭字符流,则缓冲区中的内容是无法输出的。如果想在不关闭时也可以将字符流的内容全部输出,则可以使用Writer类中的flush()方法完成。
    在从字节流转化为字符流时,实际上就是byte[]转化为String的过程,方法public String(byte bytes[], String charsetName),参数中有一个关键的参数字符集编码,通常我们都省略了,系统就用操作系统的lang;而在字符流转化为字节流时,实际上是String转化为byte[]时,方法byte[]  String.getBytes(String charsetName),也是同样的道理。

    文件操作中的缓冲,指一段指定的内存,用来暂存文件IO数据流中的数据,应用缓冲的目的是提高代码中频繁进行数据写入或读出的效率。当满足如下任何一个条件时,缓冲器的数据流依次批处理程序读入或写出到输出设备:缓冲器满,关闭文件(调用close()方法),刷新缓冲(调用flush()方法)。

    文件IO异常是检查性异常,即代码中必须提供处理文件IO异常的机制,即利用try-catch程序块处理异常,或利用throw传播异常。文件IO包括如下可能发生的异常:IOException——处理IO出错时抛出的异常;EOFException——程序试图读取超出文件范围的数据时抛出的异常;FileNotFoundException——程序试图打开一个不存在文件时抛出的异常。IOException是EOFException和FileNotFoundException的超类,而其超类是Exception,直至Throwable。

    虽然文本文件与二进制文件相比,占据更多内存,但文本文件应用对字符串为主的数据流的IO处理,其好处是直观和易于操作。Java.io包中提供以Writer和Reader为超类的两组API类来进行文本文件的IO处理和操作。
    在具体文本输出代码中,按照从文件到缓冲,再到打印文本文件次序编写。如:

PrinterWriter
    -->BufferedWriter (可选项)
        -->FIleWriter

    如果无需应用缓冲,则可利用PrintWriter(File file)直接创建文件对象,进行文本文件的输出。

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class OutputWriter {

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        File file = new File("D:" + File.separator + "test.txt");
        // java.io.FileWriter.FileWriter(File file, boolean append) throws IOException
        // append if true, then bytes will be written to the end of the file rather than the beginning
        PrintWriter outPrintWriter = new PrintWriter(new BufferedWriter(
                new FileWriter(file, true)));
        outPrintWriter.print("Version: " + 1.01);
        outPrintWriter.println();
        outPrintWriter.write("File name: test.txt");
        outPrintWriter.println("此处换行");
        outPrintWriter.append("We'll see!");
        outPrintWriter.close(); // outPrintWriter.flush()也可
    }
}

    上述程序运行结果,在D盘的test.txt文件写入如下内容

    系统预设文本文件的读入操作是缓冲式输入,其常用模式为:

BufferedReader
    -->FileReader

   

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class InputReader {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        File file = new File("D:"+File.separator+"test.txt");
        BufferedReader in = new BufferedReader(new FileReader(file));
        /* 利用readLine()读取文件内容
         * String line = in.readLine();
         * while(line != null){
         *     System.out.println(line);
         *     line = in.readLine();
         * }
         * in.close();
         * */
        String line = "";
        int ch = in.read(); //读入一个字符
        while (ch != -1) {  //read()读到文件结束时,其读入内容为-1
            line += (char)ch;
            if (ch == '\n') {//遇到换行符,输出
                System.out.print(line);
                line = "";
            } else if(ch == '1') {//遇到'1',跳过3个字符
                in.skip(3);
            }
            ch = in.read();
        }
        System.out.print(line);
        in.close();
    }
}
运行结果:
Version: 1
File name: test.txt此处换行
We'll see!

    进行二进制文件输出操作的一般模式为:

DataOutputStream
    -->BufferedOutputStream (可选项,但推荐使用)
        -->FileOutputStream
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class OutputWriter2 {
    public static void main(String[] args) throws IOException {
        File file = new File("D:" + File.separator + "test2.txt");
        DataOutputStream out = new DataOutputStream(new BufferedOutputStream(
                new FileOutputStream(file)));
        out.writeBoolean(true);   //1字节
        out.writeChar(65);        //2字节
        out.writeChar('A');       //2字节
        out.writeChars("Java");   //8字节
        out.writeByte(99);        //1字节
        out.writeByte('B');       //1字节
        out.writeBytes("Coding"); //6字节
        out.writeUTF("Java");     //6字节
        out.close();
        System.out.println("File size: "+out.size()+" bytes");
    }
}

    关于上述程序中的writeBytes(String s)和writeUTF(String s),writeBytes将字符串中每个字符的高八位丢弃将低八位写入字节,所以writeBytes("Coding")写入6个字节,writeByte也类似,write('B')也丢掉了字符'B'的高字节;writeUTF是将字符串以UTF-8的格式写的,它首先用两个字节表示字符串的字节数,然后将字符按UTF-8格式写入(对于ASCII码能表示的字符,UTF-8也使用一般字节来表示),所以writeUTF("Java")写入2+4个字节。

    二进制文件输入操作一般模式:

DataInputStream
    -->BufferedInputStream (可选项,推荐使用)
        -->FileInputStream

   

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class InputReader2 {

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        File file = new File("D:" + File.separator + "test2.txt");
        DataInputStream in = new DataInputStream(new BufferedInputStream(
                new FileInputStream(file)));
        boolean flag = in.readBoolean();
        char ch1 = in.readChar();
        char ch2 = in.readChar();
        String name1 = "";
        for (int i = 0; i < 4; i++) {
            name1 += in.readChar();
        }
        byte b1 = in.readByte();
        byte b2 = in.readByte();
        byte[] bs = new byte[6];
        for (int i = 0; i < 6; i++) {
            bs[i] = in.readByte();
        }
        String name2 = in.readUTF();
        in.close();
        System.out.println(flag);
        System.out.println(ch1);
        System.out.println(ch2);
        System.out.println(name1);
        System.out.println(b1);
        System.out.println(b2);
        System.out.println(bs);
        System.out.println(name2);
    }
}

    注意:读操作时,要按写入的顺序读。上述程序的运行结果:

true
A
A
Java
99
66
[B@c17164
Java


这一篇先写到这里,下一篇写对象序列化IO和RandomAccessFile

posted on 2013-04-15 16:09  夜月升  阅读(279)  评论(0编辑  收藏  举报

导航