java io 流

java io 流

io 流总览

io.png

io 流主要提供四个接口

  • InputStream: 输入字节流
  • OutputStream: 输出字节流
  • Reader: 输入字符流
  • Writer: 输出字符流

InputStream

InputStream 输入字节流,关注字节的读取,io 包提供如下 InputStream 的实现

  • ByteArrayInputStream: 字节数组输入流
  • FileInputStream: 文件字节输入流
  • PipedInputStream: 管道输入流,可和其他的 PipedOutStream 连接,通常用于线程间通信
  • DataInputStream: 二进制数据输入流
  • ObjectInputStream: 对象输入流
  • BufferedInputStream: 带缓冲 buffer 的字节输入流
  • SequenceInputStream: 能将多个字节流合并成一个
  • PushbackInputStream: 能回退的字节流

InputStream 提供如下接口:

  • read: 从流中读取一个字节
  • read(buffer): 从流中读取字节到 buffer 中,返回真实读取的字节数
  • read(buffer, offset, length): 从流中读取 length 个字节,写入到 buffer 的 offset 处,返回真实读取的字节数
  • readNBytes(buffer, offset, length): 和 read 一样,但是保证读取 length 个字节,除非流中没有数据
  • readAllBytes: 读取所有字节,返回一个字节数组
  • skip: 跳过前 n 个字节
  • available: 剩余字节数
  • mark: 标记当前读取的位置
  • reset: 将流指针重置到上次标记的位置
  • close: 关闭流,释放资源
{
    InputStream in = new ByteArrayInputStream("0123456789".getBytes());
    assertEquals(in.read(), '0');
}
{
    InputStream in = new ByteArrayInputStream("0123456789".getBytes());
    byte[] buf = new byte[4];
    assertEquals(in.read(buf), 4);
    assertArrayEquals(buf, "0123".getBytes());
}
{
    InputStream in = new ByteArrayInputStream("0123456789".getBytes());
    byte[] buf = new byte[20];
    assertEquals(in.read(buf), 10);
    assertArrayEquals(Arrays.copyOf(buf, 10), "0123456789".getBytes());
}
{
    InputStream in = new ByteArrayInputStream("0123456789".getBytes());
    byte[] buf = new byte[20];
    assertEquals(in.read(buf, 1, 4), 4);
    assertArrayEquals(Arrays.copyOfRange(buf, 1, 1 + 4), "0123".getBytes());
}
{
    InputStream in = new ByteArrayInputStream("0123456789".getBytes());
    byte[] buf = new byte[20];
    assertEquals(in.readNBytes(buf, 1, 4), 4);
    assertArrayEquals(Arrays.copyOfRange(buf, 1, 1 + 4), "0123".getBytes());
}
{
    InputStream in = new ByteArrayInputStream("0123456789".getBytes());
    assertArrayEquals(in.readAllBytes(), "0123456789".getBytes());
}
{
    InputStream in = new ByteArrayInputStream("0123456789".getBytes());
    assertEquals(in.skip(2), 2);
    assertEquals(in.available(), 8);
    assertEquals(in.read(), '2');
    assertEquals(in.available(), 7);
    in.mark(0);
    assertEquals(in.read(), '3');
    in.reset();
    assertEquals(in.available(), 7);
    assertEquals(in.read(), '3');
    in.close();
}
{
    InputStream in = new ByteArrayInputStream("0123456789".getBytes());
    for (int ch = in.read(); ch != -1; ch = in.read()) {
        System.out.println(ch);
    }
}

OutputStream

OutputStream 输出字节流,关注字节的写入,io 包提供了如下 OutputStream 的实现

  • ByteArrayOutputStream: 输出 byte 数组
  • FileOutputStream: 文件输出流
  • PipedOutputStream: 管道输出流,可和其他的 PipedInputStream 连接,通常用于线程间通信
  • DataOutputStream: 二进制数据输出流
  • ObjectOutputStream: 对象输出流
  • BufferedOutputStream: 带缓冲 buffer 的输出流
  • SequenceOutputStream: 能将多个输出流合并成一个

OutputStream 提供如下接口:

  • write: 写入一个字节
  • write(buffer): 写入 buffer 中的数据
  • write(buffer, offset, length): 写入 buffer 从 offset 起的 length 个字节的数据
  • flush: 将缓冲区的数据刷到实际的存储中
  • close: 关闭流
OutputStream out = new ByteArrayOutputStream();
out.write('0');
out.write("123456789".getBytes());
out.write("0123456789".getBytes(), 1, 2);
out.flush();
out.close();

Reader

Reader 字符输入流,关注字符的读取,io 包提供如下 Reader 的实现

  • CharArrayReader: 字符数组输入流
  • FileReader: 文件字符输入流
  • PipedReader: 管道输入流,可以和 PipedWriter 连接,通常用于线程间通信
  • StringReader: 字符串输入流
  • BufferedReader: 带缓冲 buffer 的字符输入流
  • LineNumberReader: 带行号的字符输入流
  • PushbackReader: 能回退的字符输入流
  • InputStreamReader: 输入字节流转字符流

Reader 提供如下接口:

  • read: 从流中读取一个字符
  • read(buffer): 从流中读取字符到 buffer 中,返回真实读取的字符数
  • read(buffer, offset, length): 从流中读取 length 个字符,写入到 buffer 的 offset 处,返回真实读取的字符数
  • read(CharBuffer: 从流中读取字符到 CharBuffer 中,返回真实读取的字符数
  • skip: 跳过前 n 个字符
  • mark: 标记当前读取的位置
  • reset: 将流指针重置到上次标记的位置
  • close: 关闭流,释放资源
{
    Reader reader = new CharArrayReader("0123456789".toCharArray());
    assertEquals(reader.read(), '0');
}
{
    Reader reader = new CharArrayReader("0123456789".toCharArray());
    char[] buf = new char[4];
    assertEquals(reader.read(buf), 4);
    assertArrayEquals(buf, "0123".toCharArray());
}
{
    Reader reader = new CharArrayReader("0123456789".toCharArray());
    char[] buf = new char[20];
    assertEquals(reader.read(buf), 10);
    assertArrayEquals(Arrays.copyOf(buf, 10), "0123456789".toCharArray());
}
{
    Reader reader = new CharArrayReader("0123456789".toCharArray());
    char[] buf = new char[20];
    assertEquals(reader.read(buf, 1, 4), 4);
    assertArrayEquals(Arrays.copyOfRange(buf, 1, 1 + 4), "0123".toCharArray());
}
{
    Reader reader = new CharArrayReader("0123456789".toCharArray());
    CharBuffer buf = CharBuffer.allocate(20);
    assertEquals(reader.read(buf), 10);
}
{
    Reader reader = new CharArrayReader("0123456789".toCharArray());
    assertTrue(reader.ready());
    assertEquals(reader.skip(2), 2);
    assertEquals(reader.read(), '2');
    reader.mark(0);
    assertEquals(reader.read(), '3');
    reader.reset();
    assertEquals(reader.read(), '3');
    reader.close();
}
{
    Reader reader = new CharArrayReader("0123456789".toCharArray());
    for (int ch = reader.read(); ch != -1; ch = reader.read()) {
        System.out.println(ch);
    }
}

Writer

Writer 字符输出流,关注字符的写入,io 包提供如下 Writer 的实现

  • CharArrayWriter: 字符数组输出流
  • FileWriter: 文件字符输出流
  • PipedWriter: 管道输出流,可以和 PipedReader 连接,通常用于线程间通信
  • StringWriter: 字符串输出流
  • BufferedWriter: 带缓冲 buffer 的字符输出流
  • OutputStreamWriter: 输出字节流转字符流

Writer 提供如下接口:

  • write(char): 写入一个字符
  • write(string): 写入一个字符串
  • write(string, offset, length): 写入 string 从 offset 起的 length 个字符的数据
  • write(char[]): 写入字符数组中的数据
  • write(char[], offset, length): 写入字符数组从 offset 起的 length 个字符的数据
  • append(ch): 写入一个字符,和 write 一样
  • append(CharSequence): 写入字符序列的所有数据(String, StringBuilder, StringBuffer 都是 CharSequence 的子类)
  • append(CharSequence, offset, length): 写入字符序列从 offset 起的 length 个字符的数据
  • flush: 将缓冲区的数据刷到实际的存储中
  • close: 关闭流
Writer writer = new CharArrayWriter();
writer.write('0');
writer.write("0123456789");
writer.write("0123456789", 1, 4);
writer.write("0123456789".toCharArray());
writer.write("0123456789".toCharArray(), 1, 4);
writer.append('0');
writer.append(new StringBuilder("0123456789"));
writer.append(new StringBuilder("0123456789"), 1, 4);
writer.flush();
writer.close();

文件字节流

文件字节流关注文件的读取和写入

{
    FileOutputStream fout = new FileOutputStream("/tmp/test.txt");
    fout.write("No patient who, who has no wisdom".getBytes());
    fout.close();
}
{
    FileInputStream fin = new FileInputStream("/tmp/test.txt");
    assertArrayEquals(fin.readAllBytes(), "No patient who, who has no wisdom".getBytes());
    fin.close();
}

缓冲字节流

缓冲字节流采用装饰者模式,装饰在其他流上,使流拥有了缓存功能,从而提高读写了效率

{
    BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream("/tmp/test.txt"));
    bout.write("People lack the willpower, rather than strength".getBytes());
    bout.close();
}
{
    BufferedInputStream bin = new BufferedInputStream(new FileInputStream("/tmp/test.txt"));
    assertArrayEquals(bin.readAllBytes(), "People lack the willpower, rather than strength".getBytes());
    bin.close();
}

二进制字节流

二进制字节流关注在基本数据类型的读取和写入,采用装饰者模式,能装饰在其他流上

DataOutputStreamOutputStream 的基础上新增了如下接口:

  • writeBoolean: 写入一个 boolean 值
  • writeByte: 写入一个字节
  • writeShort: 写入一个短整型
  • writeInt: 写入一个整型
  • writeLong: 写入一个长整型
  • writeFloat: 写入一个浮点型
  • writeDouble: 写入一个双精度浮点型
  • writeChar: 写入一个字符
  • writeUTF: 写入一个 unicode 字符串

DataInputStreamInputStream 的基础上新增了如下接口:

  • readBoolean: 读取一个 boolean 值
  • readByte: 读取一个字节
  • readShort: 读取一个 short
  • readInt: 读取一个整型
  • readLong: 读取一个长整型
  • readFloat: 读取一个浮点型
  • readDouble: 读取一个双精度浮点型
  • readChar: 读取一个字符
  • readUTF: 读取一个 unicode 字符串
{
    DataOutputStream dout = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("/tmp/test.txt")));
    dout.writeBoolean(false);
    dout.writeByte('x');
    dout.writeShort(123);
    dout.writeInt(123456);
    dout.writeLong(123456789);
    dout.writeFloat((float) 123.456);
    dout.writeDouble(123.456);
    dout.writeUTF("Rome wasn’t built in one day");
    dout.close();
}
{
    DataInputStream din = new DataInputStream(new BufferedInputStream(new FileInputStream("/tmp/test.txt")));
    assertEquals(din.readBoolean(), false);
    assertEquals(din.readByte(), 'x');
    assertEquals(din.readShort(), 123);
    assertEquals(din.readInt(), 123456);
    assertEquals(din.readLong(), 123456789);
    assertEquals(din.readFloat(), (float) 123.456);
    assertEquals(din.readDouble(), 123.456);
    assertEquals(din.readUTF(), "Rome wasn’t built in one day");
    din.close();
}

对象字节流

对象字节流关注对象的写入和读取,同时拥有二进制字节流的所有功能,同样采用装饰者模式

ObjectOutputStream 相比 DataOutputStream 新增了如下接口:

  • writeObject: 写入任何 Serializable 对象

ObjectInputStream 相比 DataInputStream 新增了如下接口:

  • readObject: 从流中读取一个对象
{
    ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("/tmp/test.txt")));
    oout.writeBoolean(false);
    oout.writeByte('x');
    oout.writeShort(123);
    oout.writeInt(123456);
    oout.writeLong(123456789);
    oout.writeFloat((float) 123.456);
    oout.writeDouble(123.456);
    oout.writeUTF("Nothing is impossible to a willing heart");
    oout.writeObject(new Point(123, 456));
    oout.close();
}
{
    ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(new FileInputStream("/tmp/test.txt")));
    assertEquals(oin.readBoolean(), false);
    assertEquals(oin.readByte(), 'x');
    assertEquals(oin.readShort(), 123);
    assertEquals(oin.readInt(), 123456);
    assertEquals(oin.readLong(), 123456789);
    assertEquals(oin.readFloat(), (float) 123.456);
    assertEquals(oin.readDouble(), 123.456);
    assertEquals(oin.readUTF(), "Nothing is impossible to a willing heart");
    Point point = (Point) oin.readObject();
    assertEquals(point.x, 123);
    assertEquals(point.y, 456);
    oin.close();
}

回退字节流

可回退字节流内部维护了一个固定大小的缓冲区(可通过构造函数配置 buffer 的大小),允许将字节回退到缓冲区,如果超过了缓冲区大小,会抛出异常

PushbackInputStreamInputStream 的基础上新增了如下接口:

  • unread: 回退一个字节
  • unread(buffer): 将 buffer 中的数据回退到流的缓冲区
  • unread(buffer, offset, length): 从 buffer 的 offset 处回退 length 个字节到流缓冲区
PushbackInputStream pin = new PushbackInputStream(new ByteArrayInputStream("Failure is the mother of success".getBytes()), 10);
byte[] buf = new byte[7];
assertEquals(pin.read(buf), 7);
assertArrayEquals(buf, "Failure".getBytes());
pin.unread(buf);
assertEquals(pin.read(buf), 7);
assertArrayEquals(buf, "Failure".getBytes());
// 超过 buffer 的大小,抛出 IOException
assertThrows(IOException.class, () -> pin.unread("01234567890".getBytes()));

SequenceInputStream

SequenceInputStream 将多个 InputStream 合并成一个

InputStream in1 = new ByteArrayInputStream("For man is man and master of his fate\n".getBytes());
InputStream in2 = new ByteArrayInputStream("Cease to struggle and you cease to live\n".getBytes());
Vector<InputStream> vi = new Vector<>(List.of(in1, in2));
SequenceInputStream sin = new SequenceInputStream(vi.elements());
assertArrayEquals(sin.readAllBytes(), "For man is man and master of his fate\nCease to struggle and you cease to live\n".getBytes());

管道字节流

PipedInputStreamPipedOutputStream 通过调用 connect 方法建立连接,往 PipedOutputStream 写入,能从 PipedInputStream 读取,这种管道模式是一对一的,对一个管道流建立两次连接会抛出异常

PipedOutputStreamOutputStream 的基础上提供如下接口:

  • connect: 与一个 PipedInputStream 建立连接,如果已经建立连接,将抛出异常

PipedInputStreamInputStream 的基础上提供如下接口:

  • connect: 与一个 PipedOutputStream 建立连接,如果已经建立连接,将抛出异常
ExecutorService es = Executors.newCachedThreadPool();
PipedInputStream pin = new PipedInputStream();
PipedOutputStream pout = new PipedOutputStream();
pin.connect(pout);

es.execute(() -> {
    try {
        ObjectOutputStream oout = new ObjectOutputStream(pout);
        oout.writeInt(123456);
        oout.writeUTF("如果你还没能找到让自己热爱的事业,继续寻找,不要放弃");
        oout.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
});

es.execute(() -> {
    try {
        ObjectInputStream oin = new ObjectInputStream(pin);
        assertEquals(oin.readInt(), 123456);
        assertEquals(oin.readUTF(), "如果你还没能找到让自己热爱的事业,继续寻找,不要放弃");
        oin.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
});

try {
    es.shutdown();
    while (!es.awaitTermination(1000, TimeUnit.MILLISECONDS)) {
        // nothing to do
    }
} catch (Exception e) {
    e.printStackTrace();
}

文件字符流

文件字符流关注文件的读取和写入,使用默认的 utf-8 来编码

{
    FileWriter fw = new FileWriter("/tmp/test.txt");
    assertEquals(fw.getEncoding(), "UTF8");
    System.out.println(fw.getEncoding());
    fw.write("初学者的心态;拥有初学者的心态是件了不起的事情");
    fw.flush();
    fw.close();
}
{
    FileReader fr = new FileReader("/tmp/test.txt");
    assertEquals(fr.getEncoding(), "UTF8");
    StringBuilder sb = new StringBuilder();
    for (int ch = fr.read(); ch != -1; ch = fr.read()) {
        sb.append((char) ch);
    }
    assertEquals(sb.toString(), "初学者的心态;拥有初学者的心态是件了不起的事情");
    fr.close();
}

缓冲字符流

采用装饰者模式,装饰在其他字符流上,增加缓存功能,提高读写性能。Files 提供了缓冲字符流的构造,可以指定编码

BufferedWriterWriter 的基础上,新增了如下接口:

  • newLine: 写入一个换行符

BufferedReaderReader 的基础上,新增了如下接口:

  • readLine: 读取一个行,如果没有新的行,返回 null
  • lines: 返回一个 java.util.stream.Stream,支持 java 8 的流式处理
{
    // BufferedWriter bw = new BufferedWriter(new FileWriter("/tmp/test.txt"));
    BufferedWriter bw = Files.newBufferedWriter(Paths.get("/tmp/test.txt"), Charsets.UTF_8);
    bw.write("穷则独善其身,达则兼济天下");
    bw.newLine();
    bw.write("玉不琢、不成器,人不学、不知义");
    bw.newLine();
    bw.close();
}
{
    // BufferedReader br = new BufferedReader(new FileReader("/tmp/test.txt"));
    BufferedReader br = Files.newBufferedReader(Paths.get("/tmp/test.txt"), Charsets.UTF_8);
    assertEquals(br.readLine(), "穷则独善其身,达则兼济天下");
    assertEquals(br.readLine(), "玉不琢、不成器,人不学、不知义");
    assertEquals(br.readLine(), null);
    br.close();
}
{
    // BufferedReader br = new BufferedReader(new FileReader("/tmp/test.txt"));
    BufferedReader br = Files.newBufferedReader(Paths.get("/tmp/test.txt"), Charsets.UTF_8);
    assertThat(br.lines().collect(Collectors.toList()), equalTo(List.of(
            "穷则独善其身,达则兼济天下",
            "玉不琢、不成器,人不学、不知义"
    )));
    br.close();
}

StreamReaderWriter

InputStreamReaderOutputStreamWriter 能将字节流转化字符流,还可以指定编码

{
    OutputStreamWriter ow = new OutputStreamWriter(new FileOutputStream("/tmp/test.txt"), "utf-8");
    ow.write("你究竟是想一辈子卖糖水,还是希望获得改变世界的机遇");
    ow.flush();
    ow.close();
}
{
    InputStreamReader rw = new InputStreamReader(new FileInputStream("/tmp/test.txt"), "utf-8");
    StringBuilder sb = new StringBuilder();
    for (int ch = rw.read(); ch != -1; ch = rw.read()) {
        sb.append((char) ch);
    }
    assertEquals(sb.toString(), "你究竟是想一辈子卖糖水,还是希望获得改变世界的机遇");
    rw.close();
}

字符串流

字符串构建的流

{
    StringWriter sw = new StringWriter();
    sw.write("学而不思则罔,思而不学则殆");
    assertEquals(sw.getBuffer().toString(), "学而不思则罔,思而不学则殆");
    sw.close();
}
{
    StringReader sr = new StringReader("一年之计在于春,一日之计在于晨");
    StringBuilder sb = new StringBuilder();
    for (int ch = sr.read(); ch != -1; ch = sr.read()) {
        sb.append((char) ch);
    }
    assertEquals(sb.toString(), "一年之计在于春,一日之计在于晨");
}

LineNumberReader

LineNumberReader 支持行号的字符流

LineNumberReaderReader 的基础上,新增了如下接口:

  • setLineNumber: 设置开始的文件行号,默认是 1
  • getLineNumber: 获取当前的文件行号
{
    BufferedWriter bw = new BufferedWriter(new FileWriter("/tmp/test.txt"));
    bw.write("富贵不能淫\n贫贱不能移\n威武不能屈\n此之谓大丈夫\n");
    bw.close();
}
{
    LineNumberReader lr = new LineNumberReader(new BufferedReader(new FileReader("/tmp/test.txt")));
    List<String> lines = new LinkedList<>();
    for (String line = lr.readLine(); line != null; line = lr.readLine()) {
        lines.add(lr.getLineNumber() + " " + line);
    }
    assertThat(lines, equalTo(List.of(
            "1 富贵不能淫", "2 贫贱不能移", "3 威武不能屈", "4 此之谓大丈夫"
    )));
}

回退字符流

可回退字符流内部维护了一个固定大小的缓冲区(可通过构造函数配置 buffer 的大小),允许将字符回退到缓冲区,如果超过了缓冲区大小,会抛出异常

PushbackReaderReader 的基础上新增了如下接口:

  • unread: 回退一个字符
  • unread(cbar[]): 将 buffer 中的数据回退到流的缓冲区
  • unread(char[], offset, length): 从 buffer 的 offset 处回退 length 个字节到流缓冲区
PushbackReader pr = new PushbackReader(new StringReader("蚍蜉撼大树,可笑不自量"), 10);
char[] buf = new char[5];
assertEquals(pr.read(buf), 5);
assertArrayEquals(buf, "蚍蜉撼大树".toCharArray());
pr.unread(buf);
assertEquals(pr.read(buf), 5);
assertArrayEquals(buf, "蚍蜉撼大树".toCharArray());
// 超过 buffer 的大小,抛出 IOException
assertThrows(IOException.class, () -> pr.unread("01234567890".toCharArray()));

管道字符流

PipedReaderPipedWriter 通过调用 connect 方法建立连接,往 PipedWriter 写入,能从 PipedReader 读取,这种管道模式是一对一的,对一个管道流建立两次连接会抛出异常

PipedWriterWriter 的基础上提供如下接口:

  • connect: 与一个 PipedReader 建立连接,如果已经建立连接,将抛出异常

PipedReaderReader 的基础上提供如下接口:

  • connect: 与一个 PipedWriter 建立连接,如果已经建立连接,将抛出异常
ExecutorService es = Executors.newCachedThreadPool();
PipedReader pr = new PipedReader();
PipedWriter pw = new PipedWriter();
pr.connect(pw);

es.execute(() -> {
    try {
        BufferedWriter bw = new BufferedWriter(pw);
        bw.write("活着就是为了改变世界,难道还有其他原因吗");
        bw.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
});

es.execute(() -> {
    try {
        BufferedReader br = new BufferedReader(pr);
        assertEquals(br.readLine(), "活着就是为了改变世界,难道还有其他原因吗");
        br.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
});

try {
    es.shutdown();
    while (!es.awaitTermination(1000, TimeUnit.MILLISECONDS)) {
        // nothing to do
    }
} catch (Exception e) {
    e.printStackTrace();
}

链接

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容

  • 一、IO流的概念 Java的IO流是实现输入/输出的基础,它可以方便地实现数据的输入/输出操作,在Java中把不同...
    Android进阶与总结阅读 1,737评论 0 7
  • Java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。Java.io 包中的...
    Marlon666阅读 185评论 0 0
  • 1.流的分类 (1)输入输出流输入输出是针对程序运行的内存而言的输入流的基类:InputStream,Reader...
    ql2012jz阅读 569评论 0 3
  • 本篇文章主要围绕字符编码展开,为了能够更好地讲述这一主题,我将从字节流操作中文数据开始。 字节流操作中文数据 假设...
    北京大数据苏焕之阅读 396评论 0 0
  • 标准输入输出,文件的操作,网络上的数据流,字符串流,对象流,zip文件流等等,java中将输入输出抽象称为流,就好...
    navy_legend阅读 699评论 0 0