Skip to main content
Jkyo Chen Blog

第一章 流与文件

流与文件 #

#

读写字节 #

InputStream
abstract int read() //读入一个字节,并返回读入的字节。遇到输入源结尾时返回 -1。

Sustem.in //是 InputStream 的一个子类的预定义对象。
// 从键盘读入信息

OutputStream
abstract void write(int b) // 可以向某个输出位置写出一个字节。
// available 不会被阻塞,阻塞意味着当前线程将失去它对资源的占用。
int bytesAvailable = in.available();
if(bytesAvailable > 0)
{
    byte[] data = new byte[bytesAvailable];
    in.read(data);
}
java.io.InputStream 1.0
abstract int read()
int read(byte[] b) // 读入一个字节数组,并返回实际读入的字节数,或者在碰到流的结尾时返回 -1 。最多读入 b.length 个字节
int read(byte[] b, int off, int len) // off 第一个读入字节应该被放置的位置在 b 中的偏移量
// len 读入字节的最大数量
long skip(long n) // 在输入流中跳过 n 个字节,返回实际跳过的字节数(如果碰到流的结尾,则可能小于 n)
int available()
void close() // 关闭这个输入流
void mark(int readlimit) // 在输入流的当前位置打一个标记(并非所有流都支持这个特性)。如果输入流中已经读入的字节多于 readlimit 个,则这个流允许忽略这个标记。
void reset() // 返回到最后一个标记,随后对 read 的调用将重新读入这些字节。如果当前没有任何标记,则这个流不被重置。
boolean markSupported() // 如果这个流支持打标记,则返回 true

java.io.OutputStream 1.0
abstract void write(int n)
void write(byte[] b)
void write(byte[] b, int off, int len) // 写入所有字节或者某个范围的字节到数组 b 中。
void close(); // 冲刷并关闭输出流
void flush(); // 冲刷输出流,也就是将所有缓冲带数据发送到目的地。

完整的流家族 #

Closeable
void close() throws IOException

Flushable
void flush()
// Readable 接口只有一个方法:
int read(CharBuffer cb)
// Appendable 接口有两个用于添加单个字符和字符序列的方法
Appendable append(char c)
Appendable append(CharSequence s)
java.io.Closeable 5.0
void close() // 关闭这个 Closeable ,这个方法可能会抛出 IOException

java.io.Flushable 5.0
void flush() // 冲刷这个 Flushable

java.lang.Readable 5.0
int read(CharBuffer cb) // 尝试着向 cb 读入其可持有数量的 char 值。返回读入的 char 值的数量,或者当从这个 Readable 中无法再获得更多的值时返回 -1 。

java.lang.Appendable 5.0
Appendable append(char c)
Appendable append(CharSequence cs) // 向这个 Appendable 中追加给定的码元或者给定的序列中的所有码元,返回 this。

java.lang.CharSequence 1.4
char charAt(int index) // 返回给定索引处的码元
int length() // 返回在这个序列中的码元的数量
CharSequence subSequence(int starIndex, int endIndex) // 返回由存储在 startIndex 到 endIndex-1 处的所有码元构成的 CharSequence
String toString() // 返回这个序列中所有码元构成的字符串。

组合流过滤器 #

FileInputStream fin = new FileInputStream("employee.dat");
// 查看在用户目录下名为 "emlyee.dat" 的文件

// java.io 中的类都将相对路径名解释为以用户工作目录开始
System.getProperty("user.dir"); // 获得用户工作目录
byte b = (byte)fin.read();

DataInputStream din = ...;
double s = din.readDouble();
FileInputStream fin = new FileInputStream("employee.dat");
DataInputStream din = new DataInputStream(fin);
double s = din.readDouble();
DataInputStream din = new DataInputStream(
    new BufferedInputStream(
        new FileInputStream("employee.dat")
    )
);
PushbackInputStream pbin = new PushbackInputStream(
    new BufferedInputStream(
        new FileInputStream("employee.dat")
    )
);
// 预读下一个字节:
int b = pbin.read();
// 并非期望的值,将其推回流中
if(b != '<') pbin.unread(b);

// 读入和推回是可应用于可回推(pushback)输入流的仅有的方法。

DataInputStream din = new DataInputStream(
    pbin = new PushbackInputStream(
        new BufferedInputStream(
            new FileInputStream("employee.dat")
        )
    )
);
ZipInputStream zin = new ZipInputStream(new FileInputStream("emplyee.zip"));
DataInputStream din = new DataInputStream(zin);
java.io.FileInputStream 1.0
FileInputstream(String name)
FilieInputStream(File file)
// 使用由 name 字符串或 file 对象指定路径名的文件创建一个新的文件输入流。非绝对的路径名将按照相对于 VM 启动时所设置的工作目录来解析。

java.io.FileOutputStream 1.0
FileOutputStream(String name)
FileOutputStream(String name, boolean append)
FileOutputStream(File file)
FileOutputStream(File file, boolean append)
// 使用由 name 字符串或 file 对象指定路径名的文件创建一个新的文件输入流。
// 如果 append 参数为 true,那么数据将被添加到文件尾,而具有相同名字的已有文件不会被删除;否则,这个方法会删除所有具有相同名字的已有文件

java.io.BufferedInputStream 1.0
BufferedInputStream(InputStream in)
// 创建一个带缓冲区的流。带缓冲区的输入流在从流中读入字符时,不会每次都对设备访问。当缓冲区为空时,会向缓冲区中读入一个新的数据块。

java.io.BufferedOutputStream 1.0
BufferedOutputStream(OutputStream out)
// 创建一个带缓冲区的流。带缓冲区的输出流在收集要写出的字符时,不会每次都对设备访问。当缓冲区填满或当流被冲刷时,数据就被写出。

java.io.PushbackInputStream 1.0
PushbackInputStream(InputStream in)
PushbackInputStream(InputStream in, int size)
// 构建一个可以预览一个字节或者具有指定尺寸的回推缓冲区的流。
void unread(int b)
// 回推一个字节,它可以在下次调用 read 时被再次获取。

文本输入与输出 #

InputStreamReader in = new InputStreamReader(System.in); // 假定使用主机系统默认字符编码方式。
InputStreamReader in = new InputStreamReader(new FileInputStream("kremlin.dat"), "ISO8859_5");

如何写出文本输出 #

PrintWriter out = new PrintWriter("employee.txt");
// 等同于:
PrintWriter out = new PrintWriter(new FileWriter("employee.txt"));

// 为了输出到打印写出器,需要使用与使用 System.out 时相同的 print, println 和 printf 方法。
// 可以打印数字(int, short, long, float, double),字符,boolean 值,字符串和对象。
String name = "Harry Hacker";
double salary = 75000;
out.print(name);
out.print(' ');
out.println(salary);
PrintWriter out = new PrintWriter(new FileWriter("employee.txt"), true); //启用自动冲刷机制。
java.io.PrintWriter 1.1
PrintWriter(Writer out)
PrintWriter(Writer out, boolean autoFlush)
PrintWriter(OutputStream out)
PrintWriter(OutputStream out, boolean autoflush)
PrintWriter(String filename)
PrintWriter(File file)

void print(Object obj)
void print(String s)
void println(String s)
void print(char[] s)
void print(char c)
void print(int i)
void print(long l)
void print(float f)
void print(double d)
void print(boolean b)
void printf(String format, Object... args)
boolean checkError()

如何读入文本输入 #

BufferedReader in = new BufferedReader(
    new InputStreamReader(new FileInputStream("employee.txt"), "UTF-8")
);

// readLine 方法在没有输入时返回 NULL
String line;
while((line = in.readLine()) != null)
{
    do something with line
}

以文本格式存储对象 #

// textFile/TextFileTest.java

public class TextFieTest
{
    public static void main(String[] args) throws IOException
    {
        Employee[] staff = new Employee[3];
        staff[0] = new Employee("Carl Cracker", 75000, 1987, 12, 15);
        staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
        staff[2] = new Employee("Tony Tester", 40000, 1990, 3, 15);

        try (PrintWriter out = new PrintWriter("employee.dat", "UTF-8"))
        {
            writeData(staff, out);
        }

        try (Scanner in = new Scanner(
            new FileInputStream("employee.dat"), "UTF-8"
        ))
        {
            Employee[] newStaff = readData(in);
            for(Employee e : newStaff)
                System.out.println(e);
        }
    }

    private static void writerData(Employee[] employees, PrintWriter out) throws IOException
    {
        out.println(employees.length);

        for(Employee e : employees)
            writeEmployee(out, e);
    }

    private static Employee[] readData(Scanner in)
    {
        int n = in.nextInt();
        in.nextLine();

        Employee[] employees = new Employee[n];
        for(int i = 0; i < n; i++)
        {
            employees[i] = readEmployee(in);
        }
        return employees;
    }

    public static void writeEmployee(PrintWriter out, Employee e)
    {
        GregorianCalendar calendar = new GregorianCalendar();
        calendar.setTime(e.getHiredDay());
        out.println(e.getName() + "|" + e.getSalary() + "|" + calendar.get(Calendar.YEAR) + "|" + (calendar.get(Calendar.MONTH) + 1) + "|" + calendar.get(Calendar.DAY_OF_MONTH));
    }

    public static Employee readEmployee(Scanner in)
    {
        String line = in.nextLine();
        String[] tokens = line.split("\\|");
        String name = tokens[0];
        double salary = Double.parseDouble(tokens[1]);
        int year = Integer.parseInt(tokens[2]);
        int month = Integer.parseInt(tokens[3]);
        int day = Integer.parseInt(tokens[4]);
        return new Employee(name, salary, year, month, day);
    }
}

字符集 #

// aliases 方法返回由别名构成的 Set 对象。
Set aliases = cset.aliases();
for(String alias : aliases)
    System.out.println(alias);

// 字符集名字大小写是不敏感的。

Charset cset = Charset.forName("ISO-8859-1");

// 为了确定在某个特定实现中哪些字符集是可用的
Map charsets = Charset.availableCharsets();
for(String name : charsets.keySet())
    System.out.println(name);
// 编码
String str = ...;
ByteBuffer buffer = cset.encode(str);
byte[] bytes = buffer.array();

// 解码
byte[] bytes = ...;
ByteBuffer bbuf = ByteBuffer.wrap(bytes, offset, length);
CharBuffer cbuf = cdet.decode(bbuf);
String str = cbuf.toString();
java.nio.charset.Charset 1.4
static SorteMap availableCharsets()
static Charset forName(String name)
Set aliases()
ByteBuffer encode(String str)
CharBuffer decode(ByteBuffer buffer)

java.nio.ByteBuffer 1.4
byte[] arrray[]
static ByteBuffer wrap(byte[] bytes)
static ByteBuffer wrap(byte[] bytes, int offset, int length)
// 返回管理给定字节数组或给定字节数组的某个范围的字节缓冲区。

java.nio.charBuffer
char[] array() // 返回这个缓冲区所管理的码元数组
char charAt(int index)
String toString() // 返回由这个缓冲区所管理的码元构成的字符串

读写二进制 #