IO技术概述

  • Output 把内存中的数据存储到持久化设备上这个动作称为输出(写)Output操作
  • Input 把持久设备上的数据读取到内存中的这个动作称为输入(读)Input操作
  • 把上面的这种输入和输出动作称为IO操作

概念

  • IO流用来处理设备之间的数据传输
  • Java对数据的操作是通过流的方式
  • Java用于操作流的类都在IO包中
  • 流按流向分为两种:输入流,输出流。
  • 流按操作类型分为两种:
    • 字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
    • 字符流 : 字符流只能操作纯字符数据,比较方便。

IO流常用父类

  • 字节流的抽象父类:
    • InputStream
    • OutputStream
  • 字符流的抽象父类:
    • Reader
    • Writer

IO程序书写

  • 使用前,导入IO包中的类
  • 使用时,进行IO异常处理
  • 使用后,释放资源

编码表

  • ascii: 一个字节中的7位就可以表示。对应的字节都是正数。0-xxxxxxx
  • iso-8859-1:拉丁码表 latin,用了一个字节用的8位。1-xxxxxxx 负数。
  • GB2312:简体中文码表。包含6000-7000中文和符号。用两个字节表示。两个字节第一个字节是负数,第二个字节可能是正数
  • GBK:目前最常用的中文码表,2万的中文和符号。用两个字节表示,其中的一部分文字,第一个字节开头是1,第二字节开头是0
  • GB18030:最新的中文码表,目前还没有正式使用。
  • unicode:国际标准码表:无论是什么文字,都用两个字节存储。
  • Java中的char类型用的就是这个码表。char c = 'a';占两个字节。
  • Java中的字符串是按照系统默认码表来解析的。简体中文版 字符串默认的码表是GBK。
  • UTF-8:基于unicode,一个字节就可以存储数据,不要用两个字节存储,而且这个码表更加的标准化,在每一个字节头加入了编码信息(后期到api中查找)。

IO中的异常处理

如果不使用try catch 可以添加抛出声明

public static void main(String[] args) throws IOException{

}
  • 保证流对象变量,作用域足够
  • catch里面,怎么处理异常
    • 输出异常的信息,目的看到哪里出现了问题
    • 停下程序,从新尝试
  • 如果流对象建立失败了,需要关闭资源吗
    • new 对象的时候,失败了,没有占用系统资源
    • 释放资源的时候,对流对象判断null
    • 变量不是null,对象建立成功,需要关闭资源
FileOutputStream fos = null;
// 注意变量的作用域问题
// try 外面声明变量,try 里面建立对象
try{
    fos = new FileOutputStream("s:\\a.txt");
    fos.write(100);
}catch(IOException ex){
    System.out.println(ex);
    throw new RuntimeException("文件写入失败,重试");
}finally{
    try{
        if(fos!=null)
          fos.close();
    }catch(IOException ex){
        throw new RuntimeException("关闭资源失败");
    }
}

字节输出流FileOutputStream类

流对象的构造方法,可以创建文件,如果文件存在,直接覆盖

Constructor and Description
FileOutputStream(File file)
创建文件输出流以写入由指定的 File对象表示的文件。
FileOutputStream(File file, boolean append)
创建文件输出流以写入由指定的 File对象表示的文件。
FileOutputStream(FileDescriptor fdObj)
创建文件输出流以写入指定的文件描述符,表示与文件系统中实际文件的现有连接。
FileOutputStream(String name)
创建文件输出流以指定的名称写入文件。
FileOutputStream(String name, boolean append)
创建文件输出流以指定的名称写入文件。
  • 创建流子类的对象,绑定数据目的
  • 调用流对象的方法write写
  • close释放资源
Modifier and Type Method and Description
void close()
关闭此文件输出流并释放与此流相关联的任何系统资源。
protected void finalize()
清理与文件的连接,并确保当没有更多的引用此流时,将调用此文件输出流的 close方法。
FileChannel getChannel()
返回与此文件输出流相关联的唯一的FileChannel对象。
FileDescriptor getFD()
返回与此流相关联的文件描述符。
void write(byte[] b)
b.length个字节从指定的字节数组写入此文件输出流。
void write(byte[] b, int off, int len)
len字节从位于偏移量 off的指定字节数组写入此文件输出流。
void write(int b)
将指定的字节写入此文件输出流。

文件的续写和换行符号

/*
* 文件的续写
* FileOutputStream构造方法, 的第二个参数中,加入true
* 换行
* 在文件中,写入换行,符号换行\r\n 可以写在上一行的末尾, 也可以写在下一行的开头
*/

File file = new File("c:\\b.txt");
FileOutputStream fos = new FileOutputStream(file,true);
fos.write("hello\r\n".getBytes());
fos.write("world".getBytes());
fos.close();

写入字节

FileOutputStream fos = new FileOutputStream("c:\\a.txt");
//流对象的方法write写数据
//写1个字节
fos.write(97);
//关闭资源
fos.close();

写入字节数组

FileOutputStream fos = new FileOutputStream("c:\\a.txt");
//流对象的方法write写数据
//写字节数组
byte[] bytes = {65,66,67,68};
fos.write(bytes);

//写字节数组的一部分,开始索引,写几个
fos.write(bytes, 1, 2);

//写入字节数组的简便方式
//写字符串
fos.write("hello".getBytes());

//关闭资源
fos.close();

字节输入流FileInputStream类

流对象的构造方法

Constructor and Description
FileInputStream(File file)
通过打开与实际文件的连接创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
FileInputStream(FileDescriptor fdObj)
创建 FileInputStream通过使用文件描述符 fdObj ,其表示在文件系统中的现有连接到一个实际的文件。
FileInputStream(String name)
通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。

流对象的所有方法

Modifier and Type Method and Description
int available()
返回从此输入流中可以读取(或跳过)的剩余字节数的估计值,而不会被下一次调用此输入流的方法阻塞。
void close()
关闭此文件输入流并释放与流相关联的任何系统资源。
protected void finalize()
确保当这个文件输入流的 close方法没有更多的引用时被调用。
FileChannel getChannel()
返回与此文件输入流相关联的唯一的FileChannel对象。
FileDescriptor getFD()
返回表示与此 FileInputStream正在使用的文件系统中实际文件的连接的 FileDescriptor对象。
int read()
从该输入流读取一个字节的数据。
int read(byte[] b)
从该输入流读取最多 b.length个字节的数据为字节数组。
int read(byte[] b, int off, int len)
从该输入流读取最多 len字节的数据为字节数组。
long skip(long n)
跳过并从输入流中丢弃 n字节的数据。

读取字节

FileInputStream fis = new FileInputStream("c:\\a.txt");
//读取一个字节,调用方法read 返回int
//使用循环方式,读取文件,  循环结束的条件  read()方法返回-1
int len = 0;//接受read方法的返回值

while( (len = fis.read()) != -1){
  System.out.print((char)len);
}
//关闭资源
fis.close();

读取字节数组

/*
 *  FileInputStream读取文件
 *   读取方法  int read(byte[] b) 读取字节数组
 *   数组作用: 缓冲的作用, 提高效率
 *   read返回的int,表示读取到多少个有效的字节数
 */

/*
 * a.txt内容
 * abcdeded
 */

FileInputStream fis = new FileInputStream("c:\\a.txt");
// 创建字节数组
byte[] b = new byte[2];

int len = fis.read(b);
System.out.println(new String(b));// ab
System.out.println(len);// 2

len = fis.read(b);
System.out.println(new String(b));// cd
System.out.println(len);// 2

len = fis.read(b);
System.out.println(new String(b));// ed
System.out.println(len);// 1

len = fis.read(b);
System.out.println(new String(b));// ed
System.out.println(len);// -1

fis.close();

对读取部分加上while循环并且把数组开到1024的长度增加读取效率,如果数组过大会占用更多的内存

FileInputStream fis = new FileInputStream("c:\\a.txt");
//创建字节数组
byte[] b = new byte[1024];

int len = 0 ;
while( (len = fis.read(b)) !=-1){
    System.out.print(new String(b,0,len));
}
fis.close();

字节流复制文件读取单个字节

/*
 *  将数据源 c:\\a.txt
 *  复制到 d:\\a.txt  数据目的
 *  字节输入流,绑定数据源
 *  字节输出流,绑定数据目的
 *  
 *  输入,读取1个字节
 *  输出,写1个字节
 */

//定义两个流的对象变量
FileInputStream fis = null;
FileOutputStream fos = null;
try{
    //建立两个流的对象,绑定数据源和数据目的
    fis = new FileInputStream("c:\\t.zip");
    fos = new FileOutputStream("d:\\t.zip");
    //字节输入流,读取1个字节,输出流写1个字节
    int len = 0 ;
    while((len = fis.read())!=-1){
        fos.write(len);
    }
}catch(IOException ex){
    System.out.println(ex);
    throw new RuntimeException("文件复制失败");
}finally{
    try{
        if(fos!=null)
            fos.close();
    }catch(IOException ex){
        throw new RuntimeException("释放资源失败");
    }finally{
        try{
            if(fis!=null)
                fis.close();
        }catch(IOException ex){
            throw new RuntimeException("释放资源失败");
        }
    }
}

字节流复制文件读取字节数组

/*
 *  字节流复制文件
 *   采用数组缓冲提高效率
 *   字节数组
 *   FileInputStream 读取字节数组
 *   FileOutputStream 写字节数组
 */

long s = System.currentTimeMillis();
FileInputStream fis = null;
FileOutputStream fos = null;
try{
    fis = new FileInputStream("c:\\t.zip");
    fos = new FileOutputStream("d:\\t.zip");
    //定义字节数组,缓冲
    byte[] bytes = new byte[1024*10];
    //读取数组,写入数组
    int len = 0 ; 
    while((len = fis.read(bytes))!=-1){
        fos.write(bytes, 0, len);
    }
}catch(IOException ex){
    System.out.println(ex);
    throw new RuntimeException("文件复制失败");
}finally{
    try{
        if(fos!=null)
            fos.close();
    }catch(IOException ex){
        throw new RuntimeException("释放资源失败");
    }finally{
        try{
            if(fis!=null)
                fis.close();
        }catch(IOException ex){
            throw new RuntimeException("释放资源失败");
        }
    }
}
long e = System.currentTimeMillis();
System.out.println(e-s);

字符输出流FileWriter类

/*
 *   字符输出流
 *     java.io.Writer 所有字符输出流的超类
 *   写文件,写文本文件
 *   
 *   写的方法 write
 *     write(int c) 写1个字符
 *     write(char[] c)写字符数组
 *     write(char[] c,int,int)字符数组一部分,开始索引,写几个
 *     write(String s) 写入字符串
 *     
 *   Writer类的子类对象 FileWriter
 *   
 *   构造方法:  写入的数据目的
 *     File 类型对象
 *     String 文件名
 *     
 *   字符输出流写数据的时候,必须要运行一个功能,刷新功能
 *   flush()
 */

FileWriter fw = new FileWriter("c:\\1.txt");

//写1个字符
fw.write(100);
fw.flush();

//写1个字符数组
char[] c = {'a','b','c','d','e'};
fw.write(c);
fw.flush();

//写字符数组一部分
fw.write(c, 2, 2);
fw.flush();

//写如字符串
fw.write("hello");
fw.flush();

fw.close();

字符输入流FileReader类

/*
 *  字符输入流读取文本文件,所有字符输入流的超类
 *    java.io.Reader
 *  专门读取文本文件
 *  
 *  读取的方法 : read()
 *   int read() 读取1个字符
 *   int read(char[] c) 读取字符数组
 *   
 *   Reader类是抽象类,找到子类对象 FileReader
 *   
 *   构造方法: 绑定数据源
 *     参数:
 *        File  类型对象
 *        String文件名
 */

FileReader fr = new FileReader("c:\\1.txt");

char[] ch = new char[1024];
int len = 0 ;
while((len = fr.read(ch))!=-1){
    System.out.print(new String(ch,0,len));
}

fr.close();

flush方法和close方法区别

  • flush()方法
  • 用来刷新缓冲区的,刷新后可以再次写出,只有字符流才需要刷新
  • close()方法
  • 用来关闭流释放资源的的,如果是带缓冲区的流对象的close()方法,不但会关闭流,还会再关闭流之前刷新缓冲区,关闭后不能再写出

字符流复制文本文件

/*
 *  字符流复制文本文件,必须文本文件
 *  字符流查询本机默认的编码表,简体中文GBK
 *  FileReader读取数据源
 *  FileWriter写入到数据目的
 */

FileReader fr = null;
FileWriter fw = null;
try{
    fr = new FileReader("c:\\1.txt");
    fw = new FileWriter("d:\\1.txt");
    char[] cbuf = new char[1024];
    int len = 0 ;
    while(( len = fr.read(cbuf))!=-1){
        fw.write(cbuf, 0, len);
        fw.flush();
    }

}catch(IOException ex){
    System.out.println(ex);
    throw new RuntimeException("复制失败");
}finally{
    try{
        if(fw!=null)
            fw.close();
    }catch(IOException ex){
        throw new RuntimeException("释放资源失败");
    }finally{
        try{
            if(fr!=null)
                fr.close();
        }catch(IOException ex){
            throw new RuntimeException("释放资源失败");
        }
    }
}