★15.I-O系统

File

相关类

  • RandomAccessFile:独立的随机访问文件读写类。

示例:列出文件夹中的目录

public static void main(String[] args) {
    final String reg = "W.*";
    File path = new File("C:\\Software\\");
    String[] list = path.list(new FilenameFilter() {
        @Override
        public boolean accept(File dir, String name) {
            return Pattern.compile(reg).matcher(name).matches();
        }
    });
    assert list != null;
    Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
    for (String dirItem : list) {
        System.out.println(dirItem);
    }
}

InputStream和OutputStream

  • InputStream和OutputStream 面向字节 (二进制)。

InputStream

  • ByteArrayInputStream:内存缓冲区作为InputStream
  • StringBufferInputStream(弃用):String作为InputStream
  • FileInputStream:文件作为InputStream
  • PipedInputStream:管道,用于多线程
  • SequenceInputStream:组合多个InputStream
  • ObjectInputStream:用于对象序列化
  • FilterInputStream(修饰器,可同时组合多个修饰器)包含:
    • DataInputStream:其中的readLine方法已弃用
    • BufferedInputStream
    • LineNumberInputStream:针对Java编写编译器
    • PushbackInputStream:针对Java编写编译器

OutputStream

  • ByteArrayOutputStream:内存缓冲区作为OutputStream
  • FileOutputStream:文件作为OutputStream
  • PipedOutputStream:管道,用于多线程
  • ObjectOutputStream:用于对象序列化
  • FilterOutputStream(修饰器,可同时组合多个修饰器)包含:
    • DataOutputStream
    • PrintStream
    • BufferedOutputStream

Stream适配器

  • InputStreamReader:将InputStream转换成Reader。
  • OutputStreamWriter:将OutputStream转换成Writer。

注意事项

  • 要使用readLine()时,选择BufferedReader而不是DataOutputStream

Reader和Writer

  • Reader和Writer面向字符。

Reader

  • FileReader
  • StringReader
  • PipedReader:管道,用于多线程
  • CharArrayReader
  • FilterReader(修饰器,可同时组合多个修饰器)包含:
    • BufferedReader
    • LineNumberReader
    • PushbackReader

Writer

  • FileWriter
  • PrintWriter:构造器接受一个String类型文件名。
  • StringWriter
  • PipedWriter:管道,用于多线程
  • CharArrayWriter
  • FilterWriter(修饰器,可同时组合多个修饰器)包含:
    • BufferedWriter
    • PrintWriter

文件读写示例

1. 字符串 to 文件

public class BufferedInputFile {
    private static String read(String filename) throws IOException {
        BufferedReader in = new BufferedReader(new FileReader(filename));
        String s;
        StringBuilder sb = new StringBuilder();
        while ((s = in.readLine()) != null) {
            sb.append(s).append("\n");
        }
        in.close();
        return sb.toString();
    }

    public static void main(String[] args) throws IOException {
        System.out.print(read("src\\BufferedInputFile.java"));
    }
}

2. 文件 to 字符串

public class BasicFileOutput {
    public static void main(String[] args) throws IOException {
        String file = "src\\BasicFileOutput.out";
        BufferedReader in = new BufferedReader(
                new StringReader(BufferedInputFile.read("src\\BasiclileOutput.java")));
        PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file)));
        int lineCount = 1;
        String s;
        while ((s = in.readLine()) != null) {
            out.println(lineCount++ + ": " + s);
        }
        out.close();
    }
}

3. 内存读写

public class MemoryInput {
    public static void main(String[] args) throws IOException {
        StringReader in = new StringReader("我是内存中的数据! ");
        int c;
        while ((c = in.read()) != -1) {
            System.out.print((char) c);
        }
    }
}

4. 格式化读写

public class StoringAndRecoveringData {
    public static void main(String[] args) throws IOException {
        DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("Data.txt")));
        out.writeDouble(3.14159);
        out.writeUTF("That was pi");
        out.writeDouble(1.41413);
        out.writeUTF("Square root of 2");
        out.close();
        DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("Data.txt")));
        System.out.println(in.readDouble());
        System.out.println(in.readUTF());
        System.out.println(in.readDouble());
        System.out.println(in.readUTF());
    }
}

5. 随机读写

public class UsineandsmAccessFile {
    private static String file = "src\\rtest.dat";

    private static void display() throws IOException {
        RandomAccessFile rf = new RandomAccessFile(file, "r");
        for (int i = 0; i < 7; i++) {
            System.out.println("Value " + i + ": " + rf.readDouble());
        }
        System.out.println(rf.readUTF());
        rf.close();
    }

    public static void main(String[] args) throws IOException {
        // 写入并输出文件
        RandomAccessFile rf = new RandomAccessFile(file, "rw");
        for (int i = 0; i < 7; i++) {
            rf.writeDouble(i * 1.414);
        }
        rf.writeUTF("The end of the file");
        rf.close();
        display();

        // 修改并输出文件
        rf = new RandomAccessFile(file, "rw");
        // 跳过5个8字节(double)的数据
        rf.seek(5 * 8);
        rf.writeDouble(333.0001);
        rf.close();
        display();
    }
}

6. 检查文件结尾

public class TestEOF {
    public static void main(String[] args) throws IOException {
        DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("src\\TestEOF.java")));
        while (in.available() != 0) {
            System.out.print((char) in.readByte());
        }
    }
}

标准I/O

主要内容

  • 标准I/O包括:System.in、System.out、System.err。
  • System类的三个重定向静态方法:setIn(InputStream)setOut(PrintStream)setErr(PrintStream)

标准I/O重定向示例

public class Redirecting {
    public static void main(String[] args) throws IOException {
        // 存储标准I/O
        InputStream sIn = System.in;
        PrintStream sOut = System.out;
        PrintStream sErr = System.err;

        BufferedInputStream in = new BufferedInputStream(new FileInputStream("src//Redirecting.java"));
        PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream("test.out")));

        // 重定向标准I/O
        System.setIn(in);
        System.setOut(out);
        System.setErr(out);

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String s;
        while ((s = br.readLine()) != null) {
            System.out.println(s);
        }
        out.close();

        // 恢复标准I/O
        System.setIn(sIn);
        System.setOut(sOut);
        System.setErr(sErr);
    }
}

启动进程示例

public class OSExecute {
    public static void main(String[] args) {
        try {
            String command = "C:\\Software\\WeChat\\WeChat.exe";
            new ProcessBuilder(command.split(" ")).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

通道

简介

  • 通道可用于提高文件读写速度

简单示例

public class GetChannel {
    private static final int BSIZE = 1024;

    public static void main(String[] args) throws Exception {
        FileChannel fc = new FileOutputStream("data.txt").getChannel();
        fc.write(ByteBuffer.wrap("Some text ".getBytes()));
        fc.close();

        fc = new RandomAccessFile("data.txt", "rw").getChannel();
        fc.position(fc.size());
        fc.write(ByteBuffer.wrap("Some more".getBytes()));
        fc.close();

        fc = new FileInputStream("data.txt").getChannel();
        ByteBuffer buff = ByteBuffer.allocate(BSIZE);
        fc.read(buff);

        // 调用ByteBuffer.flip(),让ByteBuffer从写模式转变为读模式(读变写不需要调用)
        buff.flip();
        while (buff.hasRemaining()) {
            System.out.print((char) buff.get());
        }

        buff.clear();
    }
}

使用通道复制文件

方式一

public class ChannelCopy {
    private static final int BSIZE = 1024;

    public static void main(String[] args) throws Exception {
        if (args.length != 2) {
            System.out.println("arguments: sourcefile destfile");
            System.exit(1);
        }

        FileChannel in = new FileInputStream(args[0]).getChannel();
        FileChannel out = new FileOutputStream(args[1]).getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(BSIZE);
        while (in.read(buffer) != -1) {
            buffer.flip();
            out.write(buffer);
            buffer.clear();
        }
    }
}

方式二

public class TransferTo {
    public static void main(String[] args) throws Exception {
        if (args.length != 2) {
            System.out.println("arguments: sourcefile destfile");
            System.exit(1);
        }

        FileChannel in = new FileInputStream(args[0]).getChannel();
        FileChannel out = new FileOutputStream(args[1]).getChannel();
        in.transferTo(0, in.size(), out);
        // or:
        // out.transferFrom(in, 0, in.size());
    }
}

文件通道加锁

描述

  • FileChannel.tryLock():非阻塞,不一定能获取到。
  • FileChannel.lock():阻塞,阻塞直至获取到。
  • SocketChannelDatagramChannelServerSocketChannel不需要加锁。

简单示例

public class FileLocking {
    public static void main(String[] args) throws Exception {
        FileOutputStream fos = new FileOutputStream("file.txt");
        FileLock fileLock = fos.getChannel().tryLock();
        if (fileLock != null) {
            TimeUnit.MILLISECONDS.sleep(100);
            fileLock.release();
        }
        fos.close();
    }
}

字符编码

字符编解码

public class BufferToText {
    private static final int BSIZE = 1024;

    public static void main(String[] args) throws Exception {
        // 使用UTF-8编码输入(因为源代码是UTF-8)
        FileChannel fc = new FileOutputStream("data2.txt").getChannel();
        fc.write(ByteBuffer.wrap("Some text".getBytes()));
        fc.close();

        // 使用UTF-16编码输出(因为ByteBuffer.asCharBuffer()用的是Java原生编码UTF-16)
        fc = new FileInputStream("data2.txt").getChannel();
        ByteBuffer buff = ByteBuffer.allocate(BSIZE);
        fc.read(buff);
        buff.flip();
        System.out.println("1: " + buff.asCharBuffer());
        buff.rewind();

        // 使用UTF-8编码输出
        String encoding = System.getProperty("file.encoding");
        System.out.println("2: Decoded using " + encoding + ": "
                + Charset.forName(encoding).decode(buff));
        buff.clear();

        // ======================================================================
        // 使用UTF-16编码字符串
        fc = new FileOutputStream("data2.txt").getChannel();
        fc.write(ByteBuffer.wrap("Some text".getBytes("UTF-16")));
        fc.close();

        // 使用UTF-16编码输出(因为ByteBuffer.asCharBuffer()用的是Java原生编码UTF-16)
        fc = new FileInputStream("data2.txt").getChannel();
        fc.read(buff);
        buff.flip();
        System.out.println("3:" + buff.asCharBuffer());


        // ======================================================================
        // 使用UTF-16编码输入(因为ByteBuffer.asCharBuffer()用的是Java原生编码UTF-16)
        fc = new FileOutputStream("data2.txt").getChannel();
        buff = ByteBuffer.allocate(24);
        buff.asCharBuffer().put("Some text");
        fc.write(buff);
        fc.close();

        // 使用UTF-16编码输出(因为ByteBuffer.asCharBuffer()用的是Java原生编码UTF-16)
        fc = new FileInputStream("data2.txt").getChannel();
        buff.clear();
        fc.read(buff);
        buff.flip();
        System.out.println("4:" + buff.asCharBuffer());
    }
}

输出所有的字符编码

public class AvailableCharSets {
    public static void main(String[] args) {
        SortedMap charSets = Charset.availableCharsets();
        for (String csName : charSets.keySet()) {
            System.out.print(csName);

            // 输出别名
            Iterator aliases = charSets.get(csName).aliases().iterator();
            if (aliases.hasNext()) {
                System.out.print(": ");
            }
            while (aliases.hasNext()) {
                System.out.print(aliases.next());
                if (aliases.hasNext()) {
                    System.out.print(", ");
                }
            }
            System.out.println();
        }
    }
}

Buffer

ByteBuffer

简单示例

public class ByteBufferDemo {
    private static final int BSIZE = 1024;

    public static void main(String[] args) {
        ByteBuffer bb = ByteBuffer.allocate(BSIZE);

        // 使用UTF-16编码
        bb.asCharBuffer().put("Howdy!");
        char c;
        while ((c = bb.getChar()) != 0) {
            System.out.print(c + " ");
        }
        System.out.println();

        bb.rewind();
        bb.asShortBuffer().put((short) 471142);
        System.out.println(bb.getShort());

        bb.rewind();
        bb.asIntBuffer().put(99471142);
        System.out.println(bb.getInt());

        bb.rewind();
        bb.asLongBuffer().put(99471142);
        System.out.println(bb.getLong());

        bb.rewind();
        bb.asFloatBuffer().put(99471142);
        System.out.println(bb.getFloat());

        bb.rewind();
        bb.asDoubleBuffer().put(99471142);
        System.out.println(bb.getDouble());
    }
}

注意事项

  • ByteBuffer分配空间的时候会自动置0。

其他Buffer

public class IntBufferDemo {
    private static final int BSIZE = 1024;

    public static void main(String[] args) {
        ByteBuffer bb = ByteBuffer.allocate(BSIZE);
        IntBuffer ib = bb.asIntBuffer();
        ib.put(new int[]{11, 42, 47, 99, 143, 811, 1016});
        // 获取索引为3的元素
        System.out.println(ib.get(3));

        // 用1811的覆盖索引为3的元素
        ib.put(3, 1811);
        ib.flip();
        while (ib.hasRemaining()) {
            int i = ib.get();
            System.out.println(i);
        }
    }
}

MappedByteBuffer

  • MappedByteBuffer:用于内存映射,可以将原来太大放不进内存的数据放进内存。
public class MappedByteBufferDemo {
    private static final int length = 100000;

    public static void main(String[] args) throws Exception {
        FileChannel fileChannel = new RandomAccessFile("test.dat", "rw").getChannel();
        MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, length);
        for (int i = 0; i < length; i++) {
            mappedByteBuffer.put((byte) 'x');
        }
        System.out.println("Finished writing");
        for (int i = length / 2; i < length / 2 + 6; i++) {
            System.out.println((char) mappedByteBuffer.get(i));
        }
    }
}

压缩

相关的类

  • CheckedInputStream:为InputStream产生校检。
  • CheckedOutputStream:为OutputStream产生校检。
  • DeflaterOutputStream:压缩类的基类。
    • ZipOutputStream:压缩为Zip格式。
    • GZIPOutputStream:压缩为GZIP格式。
  • InflaterInputStream:解压缩类的基类。
    • ZipInputStream:解压缩为Zip格式。
    • GZIPInputStream:解压缩为GZIP格式。

GZIP示例

public class GZIPCompress {
    public static void main(String[] args) throws IOException {
        if (args.length == 0) {
            System.out.println("Usage: \nGZlPcompress file\n" + "\tUses GZIP compression to compress " + "the file to test.gz");
            System.exit(1);
        }

        // 写入到GZIPOutputStream就是压缩
        BufferedReader in = new BufferedReader(new FileReader(args[0]));
        BufferedOutputStream out = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream("test.gz")));
        System.out.println("Writing file");
        int c;
        while ((c = in.read()) != -1) {
            out.write(c);
        }

        in.close();
        out.close();

        // 从GZIPOutputStream读取就是解压缩
        System.out.println("Reading file");
        BufferedReader in2 = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream("test.gz"))));
        String s;
        while ((s = in2.readLine()) != null) {
            System.out.println(s);
        }
    }
}

Zip示例

public class ZipCompress {
    public static void main(String[] args) throws IOException {
        // ============================压缩============================
        // 构建输出流
        FileOutputStream fileOut = new FileOutputStream("test.zip");
        CheckedOutputStream checkedOut = new CheckedOutputStream(fileOut, new Adler32());
        ZipOutputStream zipOut = new ZipOutputStream(checkedOut);
        BufferedOutputStream buffOut = new BufferedOutputStream(zipOut);

        // 设置zip的注释
        zipOut.setComment("A test of Java Zipping");

        // 压缩多个文件
        for (String arg : args) {
            System.out.println("Writing file " + arg);
            BufferedReader in = new BufferedReader(new FileReader(arg));
            // 每压缩一个文件调用ZipOutputStream.putNextEntry()一次
            zipOut.putNextEntry(new ZipEntry(arg));
            int c;
            while ((c = in.read()) != -1) {
                buffOut.write(c);
            }
            in.close();
            buffOut.flush();
        }
        buffOut.close();

        // 获取校检码
        System.out.println("Checksum: " + checkedOut.getChecksum().getValue());
        System.out.println();

        // ===========================解压缩===========================
        // 构建输入流
        FileInputStream fileIn = new FileInputStream("test.zip");
        CheckedInputStream checkedIn = new CheckedInputStream(fileIn, new Adler32());
        ZipInputStream zipIn = new ZipInputStream(checkedIn);
        BufferedInputStream buffIn = new BufferedInputStream(zipIn);

        FileOutputStream fileOut2 = new FileOutputStream("123.txt");

        // 获取每一个文件并解压到标准输出
        ZipEntry zipEntry;
        while ((zipEntry = zipIn.getNextEntry()) != null) {
            System.out.println("\nReading file " + zipEntry);
            int x;
            while ((x = buffIn.read()) != -1) {
                System.out.write(x);
            }
            System.out.flush();
        }
        if (args.length == 1) {
            System.out.println("\nChecksum: " + checkedIn.getChecksum().getValue());
        }
        buffIn.close();

        // 另一个获取ZipEntry的方式
        ZipFile zipFile = new ZipFile("test.zip");
        Enumeration enumeration = zipFile.entries();
        while (enumeration.hasMoreElements()) {
            ZipEntry ze2 = (ZipEntry) enumeration.nextElement();
            System.out.println("\nFile: " + ze2);
        }
    }
}

序列化

自动序列化

描述

  • 自动对象序列化条件:
    • 所有想要序列化的对象及其数据成员都要继承Serializable。
    • 对于不想要序列化的字段可以在前面加入transient关键字,将其排除。
    • 不会序列化或反序列化static字段。
  • 自动序列化对于两个对象引用指向相同内存的情况处理方式:只要它们序列化到同一个流中,还原时它们仍然会指向相同内存。

简单示例

class Worm implements Serializable {}

public class WormSerializer {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Worm worm1 = new Worm();

        // 方式1:序列化到文件
        ObjectOutputStream objOut1 = new ObjectOutputStream(new FileOutputStream("worm.out"));
        objOut1.writeObject("Worm storage\n");
        objOut1.writeObject(worm1);
        objOut1.close();

        ObjectInputStream objIn1 = new ObjectInputStream(new FileInputStream("worm.out"));
        String s1 = (String) objIn1.readObject();
        Worm worm2 = (Worm) objIn1.readObject();
        System.out.println(s1 + "w2 = " + worm2);


        // 方式2:序列化到内存(可用于对象深拷贝)
        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
        ObjectOutputStream objOut2 = new ObjectOutputStream(bytesOut);
        objOut2.writeObject("Worm storage\n");
        objOut2.writeObject(worm1);
        objOut2.flush();

        ObjectInputStream objIn2 = new ObjectInputStream(new ByteArrayInputStream(bytesOut.toByteArray()));
        String s2 = (String) objIn2.readObject();
        Worm worm3 = (Worm) objIn2.readObject();
        System.out.println(s2 + "w3 = " + worm3);
    }
}

手动序列化

描述

  • 手动对象序列化条件:
    • 要序列化的对象及其数据成员必须继承Externalizable。
    • 在Externalizable接口中的两个方法:writeExternal和readExternal中逐个成员调用writeObject和readObject。
    • 要序列化的对象的类及其数据成员必须有public默认构造函数。

简单示例

public class A implements Externalizable {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        A a = new A("A String ", 47);

        ObjectOutputStream objOut = new ObjectOutputStream(new FileOutputStream("A.out"));
        objOut.writeObject(a);
        objOut.close();

        ObjectInputStream objIn = new ObjectInputStream(new FileInputStream("A.out"));
        a = (A) objIn.readObject();
        System.out.println(a);
    }

    public A(String x, int a) {
        s = x;
        i = a;
    }

    public String toString() {
        return s + i;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(s);
        out.writeInt(i);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        s = (String) in.readObject();
        i = in.readInt();
    }

    private int i;
    private String s;
}

你可能感兴趣的:(★15.I-O系统)