IO流

IO就是输入输出,IO设备在计算机中起着举足轻重的作用,IO流也就是输入输出流,用来交互数据,程序和程序交互,程序也可以和网络等媒介交互。

一、IO流的分类

要分类,肯定得站得不同角度来看这个问题。

  • 根据流向划分,分为输入流和输出流
  • 根据数据的单位来分划,分为字节流和字符流
  • 根据功能划分,分为节点流和包装流
  • 还有很多

二、四大基本流

在java中IO流非常之多,但都继承于这四大基流,分别为,字节输入流(InputStream),字节输出流(OutputStream),字符输入流(Reader)和字符输出流(Writer).

它们都是抽象类,不能创建对象,只能创建它们的子类对象,阅读API发现,它们都有一个共同的方法close方法,用来关闭流,如果不关闭流的话程序会一直引用着文件。

三、模板操作

  • 创建源和目标
  • 创建流对象
  • 具体的IO操作
  • 关闭流

在下面的例子中穿插讲述

四、文件流

文件流操作是是文件。分为字符流和字节流,字节流操作是所有的二进制文件包括视频啊,图片啊什么的。字符流主要解决的还是中文的一些问题,因为中文多个字节(GBK是2个字节,UTF-8是3个字节),所有可能出现读一半或者写一半就不读了或者不写了,这样就出现乱码了。具体用字符流还是字节流得具体选择,字节流是可以操作字符流的,但是反过来就可能出现问题。输入就是从文件中读到程序中来,而输出就是从程序中输出到文件中。在这样章节记住一句话:读进来,写出去。下面操作一下各个流的常用方法,

  • 文件字节输入流(FileInputStream)

    int read() 	从此输入流中读取一个数据字节。
    int read(byte[] b) 从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中
    int read(byte[] b, int off, int len)从此输入流中将最多 len 个字节的数据读入一个 byte 数组中

    读取文件中所有的数据,用到了一个缓冲数组,也就是每次读取5个字节,直到读完为止有个len返回当前读了几个字节,如果后面没有字节了,那么它就返回-1

    //读取文件中所有的数据
    byte[] buffer = new byte[5];//定义一个缓冲数组长度为5,每次只能读取5个字节
    int len = 0;//当前读取的字节数,没有字节就返回 -1
    while((len = in.read(buffer))!= -1 ){
    String str = new String(buffer,0,len);
    System.out.println(str);
    }
  • 文件字节输出流(FileOutputStream)

    1.void write(byte[] b)
    将 b.length 个字节从指定 byte 数组写入此文件输出流中。
    2.void write(byte[] b, int off, int len)
    将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
    3.void write(int b)
    将指定字节写入此文件输出流。

    输出就是想文件中写数据,可以一次写一个字节,也可以写一个数组中的元素,这个比较简单。可以用一下四个步骤操作一下


    public class FileOutputStreamDemo {
    public static void main(String[] args) throws Exception {
    //1.创建源
    File f = new File("C:/Users/15626/Desktop/test/123.txt");
    //2.创建输出流对象
    FileOutputStream out = new FileOutputStream(f);
    //3.写操作
    out.write(97);//只能一个一个的写 //将buffer数组中的数据写在文件中
    byte[] buffer = "ABCDEF".getBytes();
    out.write(buffer); //从索引1开始的3个字节写在文件中
    out.write(buffer, 1, 3); //4.关闭资源
    out.close();
    }
    }
  • 文件字符输入流(FileReader)

    字符流的方法是从父类中继承过来的,也和上面字节流的方法大同小异

     int read()  读取单个字符。
    int read(char[] cbuf, int offset, int length) 将字符读入数组中的某一部分。
    //文件字符输入流
    public class FileReaderDemo {
    public static void main(String[] args) throws IOException {
    //1.创建源
    File src = new File("C:/Users/15626/Desktop/新建文件夹 (2)/test.txt");
    //2.创建字符输入流对象
    FileReader in = new FileReader(src);
    //3.读操作
    char[] buffer = new char[10];
    int len = -1;
    while((len = in.read(buffer)) != -1){
    String str = new String(buffer,0,len);
    System.out.println(str);
    }
    //4.关闭流
    in.close();
    }
    }
  • 文件字符输出流(FileWriter)

    void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。
    void write(int c) 写入单个字符。
    void write(String str, int off, int len) 写入字符串的某一部分。

文件的拷贝操作

把指定目录的.java文件拷贝到指定的目录


//拷贝文件:把指定目录的.java文件拷贝到指定的目录
public class FileCopyDemo2 {
public static void main(String []args) throws Exception{
//得到指定目录的文件
File srcDir = new File("C:/Users/15626/Desktop/新建文件夹 (2)");
File destDir = new File("C:/Users/15626/Desktop/新建文件夹 (2)/qqq");
//筛选出后缀是.java的文件存储在fs这个文件数组中
File[] fs = srcDir.listFiles(new FilenameFilter(){
@Override
public boolean accept(File dir, String name){
return new File(dir,name).isFile() && name.endsWith(".java");
}
});
//遍历这些文件
for (File srcFile : fs) {
//1.创建目标
File destFile = new File(destDir,srcFile.getName());
//2.创建输入流和输出流对象
FileInputStream in = new FileInputStream(srcFile);
FileOutputStream out = new FileOutputStream(destFile);
//3.输入输出操作
byte[] buffer = new byte[10];
int len = -1;
while((len = in.read(buffer)) != -1){
out.write(buffer, 0, len);
}
//4.关闭流
in.close();
out.close();
}
}
}

文件夹的拷贝

https://www.cnblogs.com/tfper/p/9855228.html

文件流正确关闭资源

https://www.cnblogs.com/tfper/p/9833722.html

五、缓冲流

缓冲流是一个包装流,目的起缓冲作用.操作流的时候,习惯定义一个byte/char数组. int read():每次都从磁盘文件中读取一个字节. 直接操作磁盘文件性能极低,为了解决这个问题,我们 定义一个数组作为缓冲区. byte[] buffer = new byte[1024]; 该数组其实就是一个缓冲区. 一次性从磁盘文件中读取1024个字节. 如此以来,操作磁盘文件的次数少了,性能得以提升,java提供的默认缓存区大小是8192(1024*8),我们一般不用修改大小.

缓冲流也有四种,分别是 BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter.操作方法都和文件流差不多,我们来看一下缓冲流到底快了多少?

/**
* @author 15626
* 操作字符或者字节流都应该用缓冲流包装起来,现在比较一下用缓冲流和不用缓冲流的情况写,复制一个文件所花费时间
* 长度的比较
*/
public class BufferCompare {
public static void main(String[] args) throws Exception {
File srcFile = new File("C:/Users/15626/Desktop/File/test.pdf");
File destFile = new File("C:/Users/15626/Desktop/File/copy.pdf");
//test1(srcFile,destFile);//不用缓冲流包装
test2(srcFile,destFile);//用缓冲流包装
}
//使用缓冲流,从内存每次读取1024个字节:15ms
public static void test2(File srcFile, File destFile) throws Exception {
long begin = System.currentTimeMillis();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(destFile)); byte[] buffer = new byte[1024];
int len = -1;
while((len = in.read(buffer)) != -1){
out.write(buffer, 0, len);
}
in.close();
out.close();
System.out.print(System.currentTimeMillis() - begin);
} //使用字节流,从磁盘中每次读取1024个字节:38ms
public static void test1(File srcFile,File destFile) throws Exception {
long begin = System.currentTimeMillis();
FileInputStream in = new FileInputStream(srcFile);
FileOutputStream out = new FileOutputStream(destFile);
byte[] buffer = new byte[1024];
int len = -1;
while((len = in.read(buffer)) != -1){
out.write(buffer, 0, len);
}
in.close();
out.close();
System.out.print(System.currentTimeMillis() - begin);
}
}

缓冲流的效率很高,所有以后操作字符字节流都可以用缓冲流包装起来。

六、内存流

内存流就是把程序中的数据暂存在内存中,在这里也就是数组中,或者把内存中的数据输出到其他媒介,内存流也是分为字节流,字符流还有一个字符串流(保存在字符串中)。简单操作一下,熟悉一个方法

import java.io.*;
/**
* @author 15626
* 字节内存流,或者说是字节数组流
* 字节内存输入流 : ByteArrayOutputStream
* 字节内存输出流 : ByteArrayInputStream
*/
public class ByteArrayStreamDemo {
public static void main(String[] args) throws Exception {
//字节内存输出流:把程序的内容写到内存中的byte数组中
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write("ABSAK".getBytes());
//把程序中的数据存在了缓冲数组中,toByteArray()方法用来获取缓冲区的数据
byte[] buffer = out.toByteArray(); //字节内存输入流: 把内存中的数据读到程序中
ByteArrayInputStream in = new ByteArrayInputStream(buffer);
byte[] by = new byte[1024];
int len = -1;
while((len = in.read(by)) != -1){
System.out.print(new String(by,0,len));
} //关闭流无效,因为本身就在存储在内存中
in.close();
out.close();
}
}
/**
* @author 15626
* 字符内存流或者说是字符数组流
* 字符内存输出流:CharArrayWriter
* 字符内存输入流:CharArrayReader
*/
public class CharArrayReaderWriterDemo {
public static void main(String[] args) throws Exception {
//字符内存输出流 : 从程序把数据存储到内存中的一个缓冲数组中
CharArrayWriter cWriter = new CharArrayWriter();
cWriter.write("你是天边最美的云彩");
//获取缓冲数组中的内容,用toCharArray()方法获取
char[] ch= cWriter.toCharArray(); //字符内存输入流:从内存中被数据读取到程序中来
CharArrayReader sReader = new CharArrayReader(ch);
char[] buffer = new char[1024];
int len = -1;
while((len = sReader.read(buffer)) != -1){
System.out.println(new String(buffer,0,len));
} //关闭流无效,因为本身就在存储在内存中
sReader.close();
cWriter.close();
}
}
/**
* @author 15626
* 字符串的内存流,把程序中的数据存储在一个缓冲字符串中
* 字符串的输出流 :StringWriter
* 字符串的输入流:StringReader
*/
public class StringWriterReaderDemo {
public static void main(String[] args) throws Exception {
//字符串的输出流
StringWriter out = new StringWriter();
out.write("你真的想成为一只帅帅气气的一只小人吗");
//获取缓冲区的字符串
//System.out.print(out.toString()); //字符串的输入流
StringReader in = new StringReader("海纳百川,有容乃大");
char[] buffer = new char[1024];
int len = -1;
while((len = in.read(buffer)) != -1){
System.out.print(new String(buffer,0,len));
} //关闭流无效,因为本身就在存储在内存中
in.close();
out.close();
}
}

要注意的关闭流无效,但是为了追求完美的格式,防止忘记了其他流的关闭,我还还是自娱自乐的关一下吧!

七、对象流

对象流包括ObjectInputStream和ObjectOutputStream,名字起得很有范,肯定是字节流

一般用对象流进行序列化和反序列化通过writeObject方法做序列化操作的,通过readObject方法做反序列化操作

1.序列化

指把堆内存中的Java对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络的节点(在网络上传输). 我们把这个过程称之为序列化.

需要做序列化的对象的类,必须实现序列化接口:java.io.Serializable接口(标志接口[没有抽象方法]). 底层会判断,如果当前对象是Serializable的实例,才允许做序列化.大多数类都已经实现了这个接口了

2.反序列化

把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象的过程.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable; /**
* @author 15626
* 对象流的序列化和反序列化操作
* ObjectInputStream 用WriterObjcet 来做序列化
* ObjectOutputStream 用ReaderObject 来做反序列化
* 需要做序列化的类必须实现Serializable接口
*/
public class ObjectStreamDemo {
public static void main(String[] args) throws Exception {
File f = new File("file/111.txt");
writeObject(f);//序列化
readObject(f);//反序列化
}
public static void readObject(File f) throws Exception{
ObjectInputStream in = new ObjectInputStream(new FileInputStream(f));
Student s = (Student)in.readObject();
System.out.println(s);
in.close(); }
public static void writeObject(File f) throws Exception {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
out.writeObject(new Student("小伙子",19,"12345"));
out.close();
}
}
class Student implements Serializable {
/**
* 做反序列化操作必须存在序列化的字节码文件,由于随着版本升级肯定字节码会发生改变,java提供了序列化版本ID,
* 可以固定这一份字节码文件,解决了这个问题
*/
private static final long serialVersionUID = 1L;
private String name;
private int age;
//密码一般不会做序列化的,静态的字段和瞬态的字段不能做序列化,所以给密码加上瞬态transient修饰符
//反序列化的结果就为null
transient private String password;
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", password=" + password + "]";
}
public Student(String name, int age, String password) {
super();
this.name = name;
this.age = age;
this.password = password;
}
}

可以看到里面有两个重要的问题,一个是反序列化对象需要对象的字节码文件,需要提供序列化ID固定这份字节码文件,还有一个是transient瞬息字段是不能序列化.

八、打印流

1.字节打印流

import java.io.File;
import java.io.PrintStream; /**
* @author 15626
* 字节打印流
* 可以自动刷新的,不想API说的那样,必须用换行符或者println才可以刷新缓冲区
*/
public class PrintStreamDemo {
public static void main(String[] args) throws Exception {
File f = new File("file/123.txt");
PrintStream p = new PrintStream(f);
p.print("aa");
p.println(121);
p.append("a");
p.close(); // System.out.println(); //这行代码等价于下面的两行代码
// PrintStream ps = System.out;
// ps.println("a");
}
}

2.字符打印流

/**
* @author 15626
* 字符打印流
* 当启用自动刷新后,即new PrintWriter(new FileOutputStream(f),true); true
* 调用println方法或者printf或者\n后进行刷新。
*
* 当不启动自动刷新,需要手动刷新,调用flush方法,或者close方法会进行刷新
*/
public class PrintWriterDemo {
public static void main(String[]args) throws Exception{
File f = new File("file/123.txt");
PrintWriter p = new PrintWriter(new FileOutputStream(f),true);
p.print("wqe");
p.println();
p.close();
}
}

IO流常规操作的更多相关文章

  1. C# IO流的操作

    C# IO流的操作非常重要,我们读写文件都会使用到这个技术,这里先演示一个文件内容复制的例子,简要说明C#中的IO操作. namespace ConsoleApplication1 { class P ...

  2. Java---IO加强(3)-IO流的操作规律

    一般写关于操作文件的读取的几个通用步骤!!! 1.明确源和目的. 源:InputStream Reader 一定是被读取的. 目的:OutputStream Writer 一定是被写入的. 2.处理的 ...

  3. C# IO流的操作(一)

    C# IO流的操作非常重要,我们读写文件都会使用到这个技术,这里先演示一个文件内容复制的例子,简要说明C#中的IO操作. namespace ConsoleApplication1 { class P ...

  4. Java文件IO流的操作总结

    Java中的IO操作涉及到的概念及相关类很多,很容易弄混,今天特来整理总结一下,并附上一份完整的文件操作的代码. 概念解析 读和写 流就是管道,向管道里面写数据用输出流:write 从管道里面读数据, ...

  5. Java API —— IO流(数据操作流 & 内存操作流 & 打印流 & 标准输入输出流 & 随机访问流 & 合并流 & 序列化流 & Properties & NIO)

    1.操作基本数据类型的流     1) 操作基本数据类型 · DataInputStream:数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型.应用程序可以使用数据输出 ...

  6. IO流的操作规律

    输入流和输出流相对于内存设备而言. 将外设中的数据读取到内存中:输入将内存的数写入到外设中:输出. 字符流的由来:其实就是:字节流读取文字字节数据后,不直接操作而是先查指定的编码表.获取对应的文字.在 ...

  7. 在c#中IO流读写操作

    1.使用FileStream读写文件 文件头: using System;using System.Collections.Generic;using System.Text;using System ...

  8. 对IO流的操作(文件大小,拷贝,移动,删除)

    import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.Fi ...

  9. java中IO流的操作

    读取转换流--读取键盘录入中键盘录入一行数据并打印其大写,发现就是读一行数据的原理.也就是readLine方法.能不能直接使用readLine方法来完成键盘录入一行数据的读取呢?readLine方法是 ...

随机推荐

  1. jmeter命令行运行与生成报告

    一.     使用命令行方式运行Jmeter 1.1 为什么 使用GUI方式启动jmeter,运行线程较多的测试时,会造成内存和CPU的大量消耗,导致客户机卡死. 所以正确的打开方式是在GUI模式下调 ...

  2. Broken pipe错误原因

      这个异常是由于以下几个原因造成. 1.客户端再发起请求后没有等服务器端相应完,点击了stop按钮,导致服务器端接收到取消请求.  通常情况下是不会有这么无聊的用户,出现这种情况可能是由于用户提交了 ...

  3. AVAudioFoundation(1):使用 AVAsset

    本文转自:AVAudioFoundation(1):使用 AVAsset | www.samirchen.com 本文主要内容来自 AVFoundation Programming Guide. 要了 ...

  4. Mindoc搭建流程

    1,安装MySql 2,官网下载:https://github.com/lifei6671/mindoc/releases mindoc_windows_amd64.7z 3,如果下载的压缩包中不存在 ...

  5. SQL学习笔记三(补充-2)之MySQL数据类型

    阅读目录 一 介绍 二 数值类型 三 日期类型 四 字符串类型 五 枚举类型与集合类型 一 介绍 存储引擎决定了表的类型,而表内存放的数据也要有不同的类型,每种数据类型都有自己的宽度,但宽度是可选的 ...

  6. CSS3:{*zoom:1;}作用

    CSS3:{*zoom:1;}作用 zoom:1的常见作用: zoom是IE专用属性,firefox等是不支持的.它的本来作用是设置或检索对象的缩放比例,但这作用几乎用不到. 可以让网页实现IE7中的 ...

  7. Mac下将C程序创建为动态链接库再由另一个C程序调用

    写C的时候需要调用之前的一个C程序,想用动态链接库的方式.Mac下的动态链接库是dylib,与Linux下的.os或Windows下的.dll不同.由于之前没有接触过,所以翻了大量的博客,然而在编译过 ...

  8. [问题解决]不使用PWM调速系统,彻底解决一个L298N带动两个电机却转速不同的问题

    问题描述:由单片机的VCC引脚供电,使用L298N控制两个电机,发现左右两个轮子的转速老是不一样,更多的情况是左轮转速高(左轮电机接OUT1和OUT2),右轮转速低(右轮电机接OUT3和OUT4)甚至 ...

  9. R:reshape2包中的melt

    melt()函数melt为熔化.溶解的意思,此处可理解为扔进去一个东西,出来另外一个本质一样但形状不一样的东西.语法结构:melt(data, ..., na.rm = FALSE, value.na ...

  10. mysql获取随机数据的方法

    order by rand() 数据多了极慢,随机性非常好,适合非常小数据量的情况. 复制代码 代码如下: SELECT * FROM table_name AS r1 JOIN (SELECT (R ...