Java IO流总结

在这里插入图片描述
在这里插入图片描述

流按操作数据类型的不同分为两种:字节流与字符流。

字节流:每次读取(写出)一个字节,当传输的资源文件有中文时,就会出现乱码。
字符流:每次读取(写出)两个字节,有中文时,使用该流就可以正确传输显示中文

流按流向分为:输入流,输出流(以程序为参照物,输入到程序,或是从程序输出)

绝对路径:一个完整的路径,以盘符开头;
相对路径:一个简化的路径,不以盘符开头。

try with resource :jdk7引入的语法糖,可以将括号内new的对象进行自动的流关闭。

0. File

简单罗列了部分常用的方法,具体方法请见jdk8文档

public File(String pathname):构造方法
File.pathSeparator指的是分隔连续多个路径字符串的分隔符,例如: java -cp test.jar;abc.jar HelloWorld 就是指“;”
File.separator是用来分隔同一个路径字符串中的目录的,可以用来加强路径字符串的平台移植性,例如: C:/Program Files/Common Files 就是指“/”
public String getAbsolutePath() :返回此File的绝对路径名字符串。
public String getPath() :将此File转换为路径名字符串。
public String getName() :返回由此File表示的文件或目录的名称。>public long length() :返回由此File表示的文件的长度。
public boolean exists() :此File表示的文件或目录是否实际存在。
public boolean isDirectory() :此File表示的是否为目录。
public boolean isFile() :此File表示的是否为文件。
public boolean createNewFile() :文件不存在,创建一个新的空文件并返回true,文件存在,不创建文件并返回false。
public boolean delete() :删除由此File表示的文件或目录。
public boolean mkdir() :创建由此File表示的目录。
public boolean mkdirs() :创建由此File表示的目录,包括任何必需但不存在的父目录。
public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。
public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录。

1. InputStream

int read():从输入流中读取一个字节的二进制数据。
int read(byte[] b):将多个字节读到数组中,填满整个数组。
int read(byte[] b, int off, int len):从输入流中读取长度为 len 的数据,从数组 b 中下标为 off 的位置开始放置读入的数据,读完返回读取的字节数,读到尾部返回-1。
void close():关闭数据流。
int available():返回目前可以从数据流中读取的字节数(但实际的读操作所读得的字节数可能大于该返回值)。
long skip(long l):跳过数据流中指定数量的字节不读取,返回值表示实际跳过的字节数。

对数据流中字节的读取通常是按从头到尾顺序进行的,如果需要以反方向读取,则需要使用回推(Push Back)操作。在支持回推操作的数据流中经常用到如下几个方法:

boolean markSupported():用于测试数据流是否支持回推操作,当一个数据流支持 mark() 和 reset() 方法时,返回 true,否则返回 false。
void mark(int readlimit):用于标记数据流的当前位置,并划出一个缓冲区,其大小至少为指定参数的大小。
void reset():将输入流重新定位到对此流最后调用 mark() 方法时的位置。

2. OutputStream

public abstract void write(int b) throws IOException //写入一个字节
public void write(byte b[]) throws IOException //可以用String的getbytes(“编码”)方法,将字符串转换成byte流输入
public void write(byte b[], int off, int len) throws IOException
public void flush() throws IOException //如果有缓冲则写入,在这个类中,这个方法为空
public void close() throws IOException //刷新并关闭流,在这个类中,这个方法为空

3. Reader

public void close() :关闭此流并释放与此流相关联的任何系统资源。
public int read(): 从输入流读取一个字符。
public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中

4. Writer

void write(int c) 写入单个字符。
void write(char[] cbuf) 写入字符数组。
abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
void write(String str) 写入字符串,Writer的核心优势
void write(String str, int off, int len) ,入字符串的某一部分,off字符串的开始索引,len写的字符个数。
void flush() 刷新该流的缓冲。
void close() 关闭此流,但要先刷新它。

5.文件读写

File + InputStream/OutputStream
File + Reader/Writer

字符流接口必须手动关闭,不然可能会丢失缓冲区的内容,建议使用try with resource

包含中文的信息传递建议用字符流。

构造方法常用的是用一个File类型的参数进行有参构造
字符流的文件输入输出方法只有构造方法;
字节流的话,方法会多一点,常用的就一个:
InputStream的public int available() throws IOException,返回的是输入流中剩余的字符数;

通常的用法是用byte[] bytes = new byte[fis.available()];来直接构造一个大小正好的byte数组,一次性进行读取。jdk9中封装的readAllBytes就是这个操作的封装。

实际上,如果读取的内容过多,还是应该通过缓冲的方式,一次次读取,避免浪费过多的资源去开辟数组空间。

输出类(OutputStream/Writer)构造方法中加一个参数true,为在文末添加(append)内容;
若不加,则默认false,为覆盖。

例1:字节流写文件与读文件

import java.io.*;

public class Test {
    public static void main(String[] args) {
        File file1 = new File("/Users/riter/Downloads/testInputStream.txt");
        File file2 = new File("/Users/riter/Downloads/testOutputStream.txt");
        try (InputStream fis = new FileInputStream(file1); OutputStream fos = new FileOutputStream(file2,true)) {
            byte[] bytes = new byte[1024];
            int len;
            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

例2:字符流读取与写入

import java.io.*;

public class Test {
    public static void main(String[] args) {
        File file1 = new File("/Users/riter/Downloads/testInputStream.txt");
        File file2 = new File("/Users/riter/Downloads/testOutputStream.txt");
        try (Reader fr = new FileReader(file1); Writer fw = new FileWriter(file2,true)) {
            char[] chars = new char[1024];
            int len;
            while ((len = fr.read(chars)) != -1) {
                fw.write(chars);
            }
            fw.write("可以通过字符串写入!!!");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

java1.7新增Files类

// 写入文件(追加方式:StandardOpenOption.APPEND)
Files.write(Paths.get(filePath), Content.getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND);

// 读取文件
byte[] data = Files.readAllBytes(Paths.get(filePath));
System.out.println(new String(data, StandardCharsets.UTF_8))

6. 转换流

将字节流转换成字符流

public InputStreamReader(InputStream in)
public OutputStreamWriter(OutputStream out)

FileWriter继承于OutputStreamWriter
FileReader继承于InputStreamReader
也就是字符流的读写都是继承于转换流的。

7. 增强流

7.1 缓冲流

它是对四种输入输出流的增强流,通俗点讲,就是可以加速流的传输

缓冲流的基本原理:
1、使用了底层流对象从具体设备上获取数据,并将数据存储到缓冲区的数组内。
2、通过缓冲区的read()方法从缓冲区获取具体的字符数据,这样就提高了效率。
3、如果用read方法读取字符数据,并存储到另一个容器中,直到读取到了换行符时,将另一个容器临时存储的数据转成字符串返回,就形成了readLine()功能。

字节缓冲流:BufferedInputStream,BufferedOutputStream
字符缓冲流:BufferedReader,BufferedWriter
构造方法:将对应的输入输出流作为参数有参构造
独有方法:(独有方法必须要用子类去实例化对象)
1) BufferedReader:public String readLine(): 读一行数据。 读取到最后返回null
2) BufferedWriter:public void newLine(): 换行,由系统属性定义符号。

补充:缓冲流搭配byte数组读取,让你体验飞一般的读写速度!

实战演练:
要求:将输入文件中的每行内容按序号排序输出到输出文件中。

6.你说你的程序叫简单,我说我的代码叫诗篇
1.一想到你我就哦豁豁豁豁豁豁豁豁豁豁…哦nima个头啊,完全不理人家受得了受不了
8.Just 简单你和我 ,Just 简单程序员
3.约了地点却忘了见面 ,懂得寂寞才明白浩瀚
5.沉默是最大的发言权
2.总是喜欢坐在电脑前, 总是喜欢工作到很晚
7.向左走 又向右走,我们转了好多的弯
4.你从来就不问我,你还是不是那个程序员

提示:
要求排序的话,可以选型treemap,因为treemap正好是按键的大小排序的,
如果要求逆序排序或其他排序方法,只要实现一个比较器就可以了(见注释);
遍历map可以用许多方法,以下列出了几种较为常见的(见注释)

import java.io.*;
import java.util.*;
import java.util.function.BiConsumer;

public class Test {
    public static void main(String[] args) {
        final TreeMap<String, String> map = new TreeMap<>(/*new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.compareTo(o1);
            }
        }*/);
        File file1 = new File("/Users/riter/Downloads/testInputStream.txt");
        File file2 = new File("/Users/riter/Downloads/testOutputStream.txt");
        try (BufferedReader br = new BufferedReader(new FileReader(file1)); BufferedWriter bw = new BufferedWriter(new FileWriter(file2))) {
            String s;
            while ((s = br.readLine()) != null) {
                final String[] content = s.split("\\.");
                map.put(content[0], content[1]);
            }
            /*for (Map.Entry<String, String> entry : map.entrySet()) {
                bw.write(entry.getKey() + ":" + entry.getValue());
                bw.newLine();
            }*/
/*            Iterator iterator = map.entrySet().iterator();
            while(iterator.hasNext()) {
                Map.Entry entry = (Map.Entry) iterator.next();
                bw.write(entry.getKey() + ":" + entry.getValue());
                bw.newLine();
            }*/
            /*for (String s1 : map.keySet()) {
                bw.write(s1 + ":" + map.get(s1));
                bw.newLine();
            }*/
            map.forEach(new BiConsumer<String, String>() {
                @Override
                public void accept(String s, String s2) {
                    try {
                        bw.write(s + ":" + s2);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    try {
                        bw.newLine();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

7.2 数据流 DataInputStream / DataOutputStream

作用:扩展InputStream和OutputStream对特定类型的读与写

DataInputStream(InputStream in)
final int read(byte[] buffer, int offset, int length)
final int read(byte[] buffer)
final boolean readBoolean()
final byte readByte()
final char readChar()
final double readDouble()
final float readFloat()
final void readFully(byte[] dst)
final void readFully(byte[] dst, int offset, int byteCount)
final int readInt()
final String readLine()
final long readLong()
final short readShort()
final static String readUTF(DataInput in)
final String readUTF() // 从输入流中读取UTF-8编码的数据,并以String字符串的形式返回
final int readUnsignedByte()
final int readUnsignedShort()

public final void writeBooolean()throws IOException,
public final void writeByte()throws IOException,
public final void writeShort()throws IOException,
public final void writeInt()throws IOException等方法(DataInputStream中,有read就有对应的write)
这些方法将指定的基本数据类型以字节的方式写入到输出流。
public final void writeBytes(String s) throws IOException
将字符串以字节序列写入到底层的输出流,字符串中每个字符都按顺序写入,并丢弃其高八位

7.3 打印流

作用:PriteWriter扩展Writer的输出方法;PrintStream扩展OutputStream的输出方法;
扩展了格式化printf,println等输出方法
使用场景:当程序需要进行内容输出,用打印流。

public PrintWriter (Writer out)
public PrintWriter(Writer out, boolean autoFlush)
public PrintWriter(OutputStream out)
public PrintWriter(OutputStream out, boolean autoFlush)
public PrintWriter(String fileName)
public PrintWriter(String fileName, String csn)
public PrintWriter(File file)
public PrintWriter(File file, String csn)

public PrintStream(OutputStream out)
public PrintStream(OutputStream out, boolean autoFlush)
public PrintStream(OutputStream out, boolean autoFlush, String encoding)
public PrintStream(String fileName)
public PrintStream(String fileName, String csn)
public PrintStream(File file)
public PrintStream(File file, String csn)

8. byte流

唯一的特点可能就是byte流的输出流是输出到内存流中。

独有方法:(独有方法必须要用子类去实例化对象)
public synchronized void writeTo(OutputStream out) throws IOException
public synchronized byte toByteArray()[]

import java.io.*;
import java.nio.charset.StandardCharsets;

public class Test {
    public static void main(String[] args) {
        try(final InputStream inputStream = new ByteArrayInputStream("abed".getBytes(StandardCharsets.UTF_8));
            final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();) {
            byte[] bytes = new byte[1024];
            int len = 0;
            while((len = inputStream.read(bytes))!=-1) {
                outputStream.write(bytes,0,len);
            }
            System.out.println(outputStream);
        } catch (IOException e) {
            e.printStackTrace();
        };
    }
}

9.管道流

线程之间通信的流

PipedInputStream
public void connect(PipedOutputStream src) throws IOException

PipedOutputStream

PipedWriter
public synchronized void connect(PipedReader snk) throws IOException

PipedReader

例子:

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.nio.charset.StandardCharsets;

class SendThread implements Runnable {
    private PipedOutputStream output;

    public SendThread() {
        this.output = new PipedOutputStream();
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                this.output.write(("num" + i).getBytes(StandardCharsets.UTF_8));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public PipedOutputStream getOutput() {
        return output;
    }
}

class ReceiveThread implements Runnable {
    private PipedInputStream input;

    public ReceiveThread() {
        input = new PipedInputStream();
    }

    @Override
    public void run() {
        final byte[] data = new byte[1024];
        int len = 0;
        while (true) {
            try {
                if (!((len = input.read(data)) != -1)) break;
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "接收:" + new String(data,0,len));
        }
        try {
            this.input.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public PipedInputStream getInput() {
        return input;
    }
}

public class Test {
    public static void main(String[] args) {
        SendThread send = new SendThread();
        ReceiveThread receive = new ReceiveThread();
        try {
            send.getOutput().connect(receive.getInput());
        } catch (IOException e) {
            e.printStackTrace();
        }
        new Thread(send, "发送线程").start();
        new Thread(receive, "接收线程").start();
    }
}

10. Scanner

BufferedReader的代替者;
实现了迭代器,并对hasnext()以及next()的方法进行了正则、大整数、自定义分隔符等扩展;
如果要实现输入,Scanner是首选

具体方法请看jdk文档。

自定义分隔符
public Scanner useDelimiter(Pattern pattern)
public Scanner useDelimiter(String pattern)

11. RandomAccessFile

需要一个大文件中间部分信息的时候可以使用,原理是将数据按照固定长度保存,然后需要某段数据的时候,就能跳字节读取。

文件存储模式:

  1. r
  2. rw
  3. rws / rwd
    解释:r = read;w = write;s = syrchronized,rws可以更新文件内容或者原数据,rwd只能更新文件内容

构造方法
public RandomAccessFile(File file, String mode)

核心方法
public int skipBytes(int n) throws IOException

12. 序列化和反序列化

实现了Seriziable接口的对象才能被序列化,transient关键字能跳过某些属性的序列化。

核心方法

public ObjectInputStream(InputStream in)
public final Object readObject()

public ObjectOutputStream(OutputStream out)
public final void writeObject(Object obj)

例子:

import java.io.*;

public class Test {
    private static final File file = new File("/Users/riter/Downloads/testInputStream.txt");
    public static void main(String[] args) {
        
    }

    public static void saveObject(Object object) throws Exception{
        try(final ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))) {
            oos.writeObject(object);//序列化
        }
    }

    public static Object loadObject() throws Exception{
        try(final ObjectInputStream ois = new ObjectInputStream(new ObjectInputStream(new FileInputStream(file)))) {
            final Object object = ois.readObject();//反序列化
            return object;
        }
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值