Java 的文件(读 写)输入输出
1、 流:
它是通过缓冲机制将数据从生产者(如键盘、磁盘文件、内存或其他设备)传送到接受该数据的消费者(如屏幕、文件或者内存等)的这一过程的抽象。
2、有关的Java包:
Java.io包中包括许多类提供许多有关文件的各个方面操作。
3、有关文件名及目录名的类:File 类独立于系统平台,利用构造函数
File( String path)、
File(String path, String FileName)、
File(File dir, String name) 等创建出File 对象;再利用canRead() 、canWrite()、 getParent()、 getPath()等成员函数实现对文件的各个属性的操作。
import java.io.*;
public class FileTest
{ public static void main(String []args)
{
String FileName="C:\\temp\\myfile.dat"
File myFile=new File(FileName);
If( ! myFile. exists() )
{ println("Can't Find " + FileName);
return;
}
System.out.println("File " + FileName + "is " +myFile.length() + "bytes Long !");
If( myFile. isDirectory() )
{ println("File" + FileName +"Is a Directory !");
return;
}
}
}
4、有关文件内容(数据)操作的类:
4.1 输入输出抽象基类InputStream/OutputStream ,实现文件内容操作的基本功能函数re
ad()、 write()、close()、skip()等;一般都是创建出其派生类对象(完成指定的特殊功能)来实现文件读写。在文件读写的编程过程中主要应该注意异常处理的技术。
4.2 FileInputStream/FileOutputStream:
用于本地文件读写(二进制格式读写并且是顺序读写,读和写要分别创建出不同的文件流对象);
本地文件读写编程的基本过程为:
生成文件流对象(对文件读操作时应该为FileInputStream类,而文件写应该为FileOutputStream类);
调用FileInputStream或FileOutputStream类中的功能函数如read()、write(int b)等)读写文件内容;
关闭文件(close())。
4.3 PipedInputStream/PipedOutputStream:
用于管道输入输出(将一个程序或一个线程的输出结果直接连接到另一个程序或一个线程的输入端口,实现两者数据直接传送。操作时需要连结);
4.3.1 管道的连接:
方法之一是通过构造函数直接将某一个程序的输出作为另一个程序的输入,在定义对象时指明目标管道对象
PipedInputStream pInput=new PipedInputStream();
PipedOutputStream pOutput= new PipedOutputStream(pInput);
方法之二是利用双方类中的任一个成员函数 connect()相连接
PipedInputStream pInput=new PipedInputStream();
PipedOutputStream pOutput= new PipedOutputStream();
t(pOutput);
4.3.2 管道的输入与输出:
输出管道对象调用write()成员函数输出数据(即向管道的输入端发送数据);而输入管道对象调用read()成员函数可以读起数据(即从输出管道中获得数据)。这主要是借助系统所提供的缓冲机制来实现的。
4.4、随机文件读写:
RandomAccessFile类(它直接继承于Object类而非InputStream/OutputStream类),从而可以实现读写文件中任何位置中的数据(只需要改变文件的读写位置的指针)。
随机文件读写编程的基本过程为:
生成流对象并且指明读写类型;
移动读写位置;
读写文件内容;
关闭文件。
StringBuffer buf=new StringBuffer();
char ch;
while( (ch=(char)ad()) !='\n')
{
buf.append( ch);
} //读写方式可以为"r" or "rw"
RandomAccessFile myFileStream=new RandomAccessFile("myFile.dat"," rw");
myFileStream . seek(myFileStream.length()) ;
myFileStream.String()); //将用户从键盘输入的内容添加到文件的尾部
myFileStream.close();
4.5 DataInput/DataOutput接口:实现与机器无关的各种数据格式读写(如readChar() 、readInt()、readLong()、readFloat(),而readLine()将返回一个String)。其中 RandomAccessFile类实现了该接口,具有比FileInputStream或FileOutputStream类更灵活的数据读写方式。
4.6 标准输入输出流:System.in(如:char c=ad())和System.out(如:System.out.println()、System.out.println())。
try
{ char ch=ad(); //返回二进制数据(低8位为键盘的ASCII码)
}
catch(IOException e)
{
}
4.7、文件操作的一般方法:
(1)生成一个输入输出文件类的对象(根据所要操作的类型);
(2)调用此类的成员函数实现文件数据内容的读写;
(3)关闭此文件。
Java 读/写文件文本文件的示例
/*
* 简单的读/写文本文件的示例
* 这里包含了三个例子,即
* 1. 将文件读入到内存(这里是StringBuffer)的例子
* 2. 将内容中的文本写到文:victory:件
* 3. 将一个文件的内容读出来写入另一个文件中
*    同时也展示了如果从输入流中读出来内容写入输出流中(仅限文本流)
* 三个例子可以独立存在,所以根据需要只看其中一个就行了。
*/

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;

public final class AccessTextFile {

    /**
     * 1. 演示将流中的文本读入一个 StringBuffer 中
     * @throws IOException
     */
    public void readToBuffer(StringBuffer buffer, InputStream is)
        throws IOException {
        String line;        // 用来保存每行读取的内容
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        line = adLine();      // 读取第一行
        while (line != null) {          // 如果 line 为空说明读完了
            buffer.append(line);        // 将读到的内容添加到 buffer 中
            buffer.append("\n");        // 添加换行符
            line = adLine();   // 读取下一行
        }
    }

    /**
     * 2. 演示将 StringBuffer 中的内容读出到流中
     */
    public void writeFromBuffer(StringBuffer buffer, OutputStream os) {
        // 用 PrintStream 可以方便的把内容输出到输出流中
        // 其对象的用法和 System.out 一样
        // (System.out 本身就是 PrintStream 对象)
        PrintStream ps = new PrintStream(os);   
        ps.String());
    }

    /**
     * 3*. 从输入流中拷贝内容到输入流中
     * @throws IOException
     */
    public void copyStream(InputStream is, OutputStream os) throws IOException {
        // 这个读过过程可以参阅 readToBuffer 中的注释
        String line;
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        PrintWriter writer = new PrintWriter(new OutputStreamWriter(os));
        line = adLine();
        while (line != null) {
            writer.println(line);
            line = adLine();
        }
        writer.flush();     // 最后确定要把输出流中的东西都写出去了
                            // 这里不关闭 writer 是因为 os 是从外面传进来的
                            // 既然不是从这里打开的,也就不从这里关闭
                            // 如果关闭的 writer,封装在里面的 os 也就被关了
    }

    /**
     * 3. 调用 copyStream(InputStream, OutputStream) 方法拷贝文本文件
     */
    public void copyTextFile(String inFilename, String outFilename)
        throws IOException {
        // 先根据输入/输出文件生成相应的输入/输出流
        InputStream is = new FileInputStream(inFilename);
        OutputStream os = new FileOutputStream(outFilename);
        copyStream(is, os);     // 用 copyStream 拷贝内容
        is.close(); // is 是在这里打开的,所以需要关闭
        os.close(); // os 是在这里打开的,所以需要关闭
    }

    public static void main(String[] args) throws IOException {
        int sw = 1;     // 三种测试的选择开关
        AccessTextFile test = new AccessTextFile();
       
        switch (sw) {
        case 1: // 测试读
        {
            InputStream is = new FileInputStream("E:\\");
            StringBuffer buffer = new StringBuffer();
            adToBuffer(buffer, is);
            System.out.println(buffer);     // 将读到 buffer 中的内容写出来
            is.close();
            break;
        }
        case 2: // 测试写
        {
            StringBuffer buffer = new StringBuffer("Only a test\n");
            test.writeFromBuffer(buffer, System.out);
            break;
        }
        case 3: // 测试拷贝
        {
            pyTextFile("E:\\", "E:\\r.txt");
        }
            break;
        }
    }

}
输入/输出(Input/Output)泛指对某个设备或环境进行数据的输入或输出。例如对硬盘进行输入/输出、对视频设备进行输入/输出、对网络主机进 行输入/输出等,可以想象,因设备或环境的不同,会有各式各样的输入/输出问题与解决方案。输入/输出问题在程序设计中实际上是一个很复杂的问题。
对于输入/输出问题,Java将之抽象化为流(Stream)对象来解决。对不同的输入/输出问题,会有相应的流对象提供解决的方案。本章就是要学习 Java中各式各样解决输入/输出问题的对象。然而输入/输出问题所涉及的领域相当广,基于学习的角度来看,必须选择一个主题
来专门讨论,所以本章主题会 围绕在文件输入/输出。有了本章的基础,在了解其他领域的输入/输出问题时就不难入手。
14.1 文件
在正式了解Java中如何处理文件输入/输出之前,要先了解一下在Java中如何表示一个文件。本小节也将简单地介绍随机文件存取,让您初步了解文件输入/输出时一些必须注意的事项。
14.1.1 File
不同的操作系统对于文件系统路径的设置各有差别。例如在Windows中,一个路径的表示法可能是:
"C:\\Workspace\\CH14\\"而在Linux下的路径设置可能会像是:
"/home/justin/workspace/ch14"Windows的路径指定是使用UNC(Universal Naming Convention)路径名,以\\开始表示硬盘根目录。如果没有以\\开始表示相对于当前工作目录的路径,C是可选的硬盘指定,后面跟随着:字符。而 UNIX-Like系统没有Windows系统的CDE这样的硬盘驱动器概念,UNIX-Like系统的路径指定以/开始表示从根目录开始的绝对路 径,不以/开始表示相对于当前工作目录的路径。
在程序中设置路径时会有系统相依性的问题,java.io.File类提供一个抽象的、与系统独立的路径表示。给它一个路径字符串,它会将其转换为与系统 无关的抽象路径表示,这个路径可以指向一个文件、目录或是URI(Uniform Resource Identifier)
一个File的实例被建立时,它就不能再被改变内容。File实例除了用作一个文件或目录的抽象表示之外,它还提供了不少相关操作方法:可以用它来对文件系统作一些查询与设置的动作。要注意的是,不管是文件还是目录,在Java中都是以File的实例来表示。
范例14.1是一个设置与操作File实例的简单示范,可以指定查询某个目录下的所有文件与目录名称。
Ü 范例14.1  FileDemo.java

package onlyfun.caterpillar;
import java.io.*;
import java.util.*;
public class FileDemo {
    public static void main(String[] args) {
        try {
            File file = new File(args[0]);
            if(file.isFile()) { // 是否为文件
               System.out.println(args[0] + " 文件");
                System.out.print(
                      file.canRead() ? "可读 " : "不可读 ");
                System.out.print(
                      file.canWrite() ? "可写 " : "不可写 ");
                System.out.println(
                      file.length() + "字节");
            }
            else {
                // 列出所有的文件及目录
               File[] files = file.listFiles();
                ArrayList<File> fileList =
                                    new ArrayList<File>();
                for(int i = 0; i < files.length; i++) {
                    // 先列出目录
                    if(files.isDirectory()) { //是否为目录
                        // 取得路径名
                        System.out.println("[" +
                                Path() + "]");
                    }
                    else {
                        // 文件先存入fileList,待会再列出
                        fileList.add(files);
                    }
                }
                // 列出文件
                for(File f: fileList) {
                    System.out.String());
                }
                System.out.println();
            }
        }
        catch(ArrayIndexOutOfBoundsException e) {
            System.out.println(
                        "using: java FileDemo pathname");
        }
    }
}

执行结果:
java onlyfun.caterpillar.FileDemo C:\
[C:\WINDOWS]
[C:\workspace]
[C:\Documents and Settings]
[C:\Program Files]
[C:\System Volume Information]
C:\pagefile.sys
C:\A3N_A3L.10
C:\bootfont.bin
C:\ntldr
...

这里先简单地介绍一下File类。File类主要是文件的抽象代表,若要作文件输出/输入,必须配合其他相关类来使用。接下来会配合各小节的内容并适时地使用File类。
14.1.2 RandomAccessFile
在正式介绍如何使用Java的输入/输出相关类来进行文件存取前,先简单地通过使用java.io.
RandomAccessFile来存取文件,以认识一些文件存取时所必须注意的概念与事项。
文件存取通常是循序的,每在文件中存取一次,文件的读取位置就会相对于目前的位置前进一次。然而有时必须指定文件的某个区段进行读取或写入的动作,也就是 进行随机存取(Random Access),即要能在文件中随意地移动读取位置。这时可以使用RandomAccessFile,使用它的seek()方法来指定文件存取的位置,指 定的单位是字节。
为了移动存取位置时的方便,通常在随机存取文件中会固定每一个数据的长度。例如长度固定为每一个学生个人数据,Java中并没有直接的方法可以写入一个固 定长度数据(C/C++中的structure),所以在固定每一个长度方面必须自行设计。范例14.2先设计一个的类。
Ü 范例14.2  Student.java

package onlyfun.caterpillar;
public class Student {
    private String name;
    private int score;
    public Student() {
        setName("noname");
    }
    public Student(String name, int score) {
        setName(name);
        this.score = score;
    }
    public void setName(String name) {
        StringBuilder builder = null;
        if(name != null)
            builder = new StringBuilder(name);
        else
            builder = new StringBuilder(15);
        builder.setLength(15); // 最长 15 字符
        this.name = String();
    }

    public void setScore(int score) {
        this.score = score;
    }
    public String getName() {
        return name;
    }
    public int getScore() {
        return score;
    }
     // 每个数据固定写入34字节
    public static int size() {
        return 34;
    }
}
java stream
对于每一个的实例在写入文件时,会固定以34字节的长度写入,也就是15个字符(30字节)加上一个int整数的长度(4字节)。范例14.2 是使用StringBuilder来固定字符长度,可以使用size()方法来取得长度信息。范例14.3则示范了如何使用 RandomAccessFile来写入文件,并可随机指定一个所想读出的数据。