黑马程序员-Java IO流

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流!——

一、概述

Java中与IO相关的类有很多,都集中在java.io中,都是以流的形式操作的,流是有一定的顺序,像一个管道一样,它的本质是传输数据。根据数据类型的不同可以分为字节流和字符流,根据流向的不同可以分为输入流和输出流。

  • 字符流:因为数据有不同的编码,可以对字符进行不同的操作,其本质还是基于字节流,然后再查询相应的码表。一般用于处理纯文本数据。
  • 字节流:可以处理所有类型数据,二进制文件(图片,音频等)。
  • 输入流:读入数据,也就是数据的源,如键盘,磁盘文件,网络文件,内存等。字符流对应的基本输入流为Reader,字节流对应的基本输入流为InputStream
  • 输出流:输出数据,数据的目的地,如控制台,磁盘文件,内存等。字符流对应的基本输出流为Writer,字节流对应的基本输出流为OutputStream

Java 所有IO流的关系如下如:

Java IO流的关系结构

二、字符流

字符流的基本输入输出流是ReaderWriter,两者有一些常用的方法:

Reader的常用读取操作:

  1. int read() 读取单个字符。
  2. int read(char[] cbuf) 将字符读入数组。
  3. abstract int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。

Writer的常用写入操作:

  1. abstract void flush() 刷新该流的缓冲。
  2. void write(char[] cbuf) 写入字符数组。
  3. void write(int c) 写入单个字符。
  4. void write(String str) 写入字符串。
  5. void write(String str, int off, int len) 写入字符串的某一部分。

在使用ReaderWriter进行数据流的读入和写入操作时是不会直接创建ReaderWriter对象的,一般都是使用其子类,如FileReaderFileWriter,示例代码如下:

import java.io.*;
class ReaderDemo {
    public static void main(String[] args) {
        FileReader reader = null;
        FileWriter writer = null;
        try {
            writer = new FileWriter("file.txt");
            // 向流中写入一个char[],内容为[‘H‘,‘e‘,‘l‘,‘l‘,‘o‘]
            writer.write("Hello".toCharArray());
            writer.flush(); // 刷新内容到磁盘上
        } catch (IOException e) {
            // IO异常在这里处理
        } finally {
            try {
                // 在finally中关闭流,并判断是否为null
                if(writer != null) {
                    writer.close();
                }
            } catch (IOException e) {}
        }

        try{
            reader = new FileReader("file.txt");
            char[] buf = new char[1024];
            int n = 0;
            // 从流中读入一个char[],然会读入的长度,-1表示到达流尾
            while((n = reader.read(buf)) != -1) {
                // 输出到屏幕上
                System.out.println(new String(buf, 0, n));
            }
        } catch (IOException e) {
            // IO异常在这里处理
        } finally {
            try {
                // 在finally中关闭流,并判断是否为null
                if(reader != null) {
                    reader.close();
                }
            } catch (IOException e) {}
        }
    }
}

上面代码有些需要注意的地方,如不管是流的创建,打开,写入,读取,刷新,关闭等操作,一般都会抛出IOException,因为对磁盘进行操作(一般都是)都有可能产生错误,如磁盘满了,文件被占用等等,所以必须对其进行捕获,并处理。流的关闭一般放在try中的finally中,原因是为防止出错后无法及时释放资源。在进行数据的写入时,当执行完write方法后,数据可能不会立即被写入到目的地,这时可以使用flush功能进行立即完成写入功能,也可以在close时自定完成内容的写入。

还有一点关于数据的读入过程,如使用int read()一个字节一个字节的读入,到达流尾时,返回-1,这种方式,需要注意其返回int需要强制转换一下,如int data = reader.read();,那么读到的数据便是(char)data;如果使用int read(char[])方式读取数据,那么就如上面代码示例的读取方式操作即可。

BufferedWriterBufferedReader使用简介

BufferedInputStreamBufferedOutputStream是为提高读取和写入的效率而出现的,当我们读取和写入数据时,可以现在内存中建立一个缓冲区,加快数据流的读写,其使用非常简单,将Reader或者Writer对象做为参数传递给其构造函数即可。功能和类似,示例代码如下:

import java.io.*;
class Demo {
    public static void main(String[] args) {
        BufferedWriter bw = null;
        try {
            bw = new BufferedWriter(new FileWriter("file.txt"));
            // 向流中写入一个char[],内容为[‘H‘,‘e‘,‘l‘,‘l‘,‘o‘]
            bw.write("Hello".toCharArray());
            bw.newLine();
            bw.flush();
        } catch (IOException e) {
            // IO异常在这里处理
        } finally {
            try {
                // 在finally中关闭流,并判断是否为null
                if(bw != null) {
                    bw.close();
                }
            } catch (IOException e) {}
        }
    }
}

其中newLine()是输出一个换行,这种操作是跨平台的,即在Windows下输出\r\n,而在Linux下输出\n

LineNumberReader使用简介

LineNumberReader单从类名上看,大致也知道了类的功能,便是可以输出文本文件的行号。这里行号是从1开始的,也可以使用setLineNumber(int)功能为其设置一个偏移值,如设置100,那么行号就会从101开始输出。示例代码如下:

import java.io.*;
class Demo {
    public static void main(String[] args) throws IOException {
        LineNumberReader reader = new LineNumberReader(new FileReader("file.txt"));
        String line = null;
        // 如果读到文件末尾则返回null
        while((line=reader.readLine()) != null ) {
            // 获取行号并输出
            System.out.println(reader.getLineNumber()+": " + line);
        }
        reader.close();
    }
}
// 执行结果为
1: Hello
2: haha
3: Hi
4: good meeas
5:
6: sa

三、字节流

字符流操作的是纯文本内容,而字节流则是所有二进制文件都可以操作,如图片,视频,当然文件文件也是可以的。与字符流中读出和写入的类型为char型相对应,字节流读出和写入的是byte类型。字节流的两个基本输入输出流为InputStreamOutputStream,其功能与字符流的功能类似。对于文件的操作的流是相应的FileInputStreamFileOutputStream,下面通过一个图片拷贝功能作为字节流的一个示例代码:

import java.io.*;
class Demo {
    public static void main(String[] args) throws IOException {

        FileInputStream fin = new FileInputStream("pic.png");
        FileOutputStream fout = new FileOutputStream("pic2.png");

        // 与Reader不同的是这里使用的是byte类型
        byte[] buf = new byte[1024];
        int n = 0;

        while((n=fin.read(buf)) != -1) {
            fout.write(buf, 0, n);
        }

        // 关闭流
        fin.close();
        fout.close();
    }
}

BufferedInputStreamBufferedOutputStream使用简介

为了提高流操作的效率,这里也用相应的缓冲流,到底使用缓冲流与不使用缓冲流在效率上有多大的差别,可以通过比较得出结果。从下面代码的比较结果可以明显的发现,加入缓冲机制会大大提高程序的运行效率,原因大致解释为,未加入缓冲机制,每次读取read()都会调用系统底层读取磁盘操作,每次读取一个字节,非常耗时;而加入缓冲机制后,系统会一次将很多内容读取到内存,而调用read()时,只需要从内存中返回数据内容即可,大大减少了系统底层访问磁盘的次数,所以速度会加快很多。代码示例如下:

import java.io.*;
class Demo {
    public static void main(String[] args) throws IOException {
        // 未加缓冲机制
        FileInputStream fin = new FileInputStream("movie.avi");
        FileOutputStream fout = new FileOutputStream("movie2.avi");
        int data = 0;
        long time1 = System.currentTimeMillis();

        while((data = fin.read()) != -1) {
            fout.write(data);
        }
        System.out.println("普通:" + (System.currentTimeMillis()-time1) + "毫秒");
        fin.close();
        fout.close();
        // 加上缓冲机制
        BufferedInputStream bfin =
            new BufferedInputStream(new FileInputStream("movie.avi"));
        BufferedOutputStream bfout =
            new BufferedOutputStream(new FileOutputStream("movie3.avi"));
        long time2 = System.currentTimeMillis();

        while((data = bfin.read()) != -1) {
            bfout.write(data);
        }
        System.out.println("缓冲:" + (System.currentTimeMillis()-time2) + "毫秒");
        bfin.close();
        bfout.close();
    }
}
// 执行结果为
普通:50052毫秒
缓冲:61毫秒

读取转换流和写入转换流

这里涉及到的两个流是关于字符流和字节流的转换的操作,去两者名称为:InputStreamReaderOutputStreamWriterInputStreamReader是将InputStream(字节流)流作为参数构造出输入字符流。而OutputStreamWriter则是将OutStream(字节流)作为参数构造出输出字符流。如此一来,我们读取键盘(System.in)数据时,便可以使用Reader的功能,也可以使用Writer功能将数据输出到控制台(System.out),示例代码如下:

import java.io.*;
class Demo {
    public static void main(String[] args) throws IOException {
        // 键盘的最常见写法。
        BufferedReader bufr =
                new BufferedReader(new InputStreamReader(System.in));

        // 使用字符输出方式到控制台
        BufferedWriter bufw =
                new BufferedWriter(new OutputStreamWriter(System.out));

        String line = null;
        while((line=bufr.readLine()) != null) {
            // 输入end时退出
            if("end".equals(line)) break;
            bufw.write(line.toUpperCase());
            bufw.newLine();
            bufw.flush();
        }
        bufr.close();
        bufw.close();
    }
}
// 执行结果为
hello
HELLO
Hi
HI
good
GOOD
end

四、流的总结

JavaIO单独封装在一个包内,其中不同功能的流数不胜数,使用起来很容易混乱,所以,在使用java io流时需要按照一定的规则,如按照流的流向可以分为两大类,即输入流和输出流,输入流来自数据源,输出流有目的地。常见的源和目的地有如下:

  • 源:键盘录入,磁盘读入,网络文件,内存。
  • 目的地:控制台输出,磁盘文件,内存。

在明确流向后,在看流的数据是否为纯文本类型,若是则优先选用ReaderWriter字符流来操作,若是二进制类型,则使用InputStreamOutputStream字节流来操作。

提高流的效率,可以使用BufferedXXX来包装流。对于编码问题,可以使用InputStreamReaderOutputStreamWriter,其可以指定编码类型,如utf-8或者GBK等。

五、File的使用简介

是将文件和文件夹封装成的对象,方便对文件或者文件夹的属性信息进行操作,也可以作为参数传递。

File常用内容

static String separator为一种夸平台文件路径分隔符。

文件的创建和删除

File file = new File("file.txt");
file.createNewFile(); // 用于创建一个空文件,成功返回true,若已存在,则不会创建并返回false,
file.delete(); // 删除成功返回true,否则返回false
file.deleteOnExit(); // 退出时删除,一般用于系统退出时删除临时文件

文件的判断

// 通过文件的目录和文件名创建一个File对象
File file = new File("c:" + File.separator + "java", "info.txt");
file.canExecute(); // 是否可被执行
file.exists(); // 是否存在
file.mkdir(); // 创建目录,一层(成功返回true,失败返回false)
file.mkdirs(); // 创建多级目录
file.isDirectory(); // 是否为目录文件,不存在或者不是目录返回false
file.isFile(); // 是否为文件,不存在或不是文件返回false
file.isHidden(); // 是否为隐藏文件
file.isAbsolute(); // 是否为据对路径
file.getName(); // 获取文件名
file.getParh(); // 获取文件路径
file.getParent(); // 父目录
file.lastModified(); // 最后修改时间

文件列表

File[] files = File.listRoots();列出有效盘符,如(C:\,D:\等)。获取文件夹内的所有文件,以及自定义指定文件,可以使用FileFilter来过滤文件。若要删除内容不为空的文件夹时,需要递归删除文件夹内的所有内容。示例代码如下:

import java.io.*;
class Demo {
    public static void main(String[] args) {

        // 列出javas\\day20目录下的java文件
        File file = new File("javas\\day20");
        File[] files = file.listFiles(new FileFilter() {
            public boolean accept(File filename) {
                // 以.java结尾的都接受
                return filename.getName().endsWith(".java");
            }
        });

        for(File f : files) {
            System.out.println(f.getName());
        }

        // 删除javas内的所有内容
        delete(new File("javas"));
    }

    /**
     * 递归删除内容不为空的文件夹或文件
     */
    public static void delete(File file) {
        if(file.isDirectory()) {
            File[] files = file.listFiles();
            for(File f : files) {
                if(f.isDirectory()) {
                    delete(f);
                } else {
                    f.delete();
                }
            }
        }
        file.delete();
    }
}
// 执行结果为
FileDemo.java
FileDemo2.java
FileDemo3.java
JavaFileList.java
PrintStreamDemo.java
PropertiesDemo.java
RemoveDir.java
RunCount.java
SequenceDemo.java
SplitFile.java

六、其他IO内容

1、改变标准输入输入流,可以使用System.setIn(InputStream)System.setOut(PrintStream)来设置标准输入输出流,可以将标准输入设置成从键盘读入,或者将标准输出设置成输出到文件等。

2、异常信息输出到文件,在捕获异常后一般使用e.printStackTrace()将异常信息输出,但是这样对用户来说是没有任何意义的,所以可以使用e.printStackTrace(new FileOutputStream("log.txt"))将异常信息输出到文件。

3、Properties简介,可以使用Properties存取配置文件,其内部有相关流操作,即load(InputStream inStream)store(OutputStream out, String comments)用于从本地读取配置文件和将配置文件保存至本地。

4、合并流SequenceInputStream可以将多个流合并成一个整体,有两种构造函数,一是将两个字节流合并成一个流(较为易懂),二是传递一个Enumeration<? extends InputStream> e类型参数,示例代码如下:

import java.io.*;
import java.util.*;
class SequenceDemo {
    public static void main(String[] args) throws IOException {
        // Vector 具有获取Enumeration功能
        Vector<FileInputStream> v = new Vector<FileInputStream>();
        v.add(new FileInputStream("1.txt"));
        v.add(new FileInputStream("2.txt"));
        v.add(new FileInputStream("3.txt"));

        // 获取流枚举
        Enumeration<FileInputStream> en = v.elements();
        // 构造合并流
        SequenceInputStream sin = new SequenceInputStream(en);
        // 将内容都写入fout
        FileOutputStream fout = new FileOutputStream("123.txt");
        byte[] buf = new byte[1024];
        int len = 0;
        while((len=sis.read(buf))!=-1) {
            fos.write(buf,0,len);
        }
        fout.close();
        sin.close();
    }
}

5、对象的序列化,实现Serializable接口,序列化即使将一个对象整个存储到文件中保存,可以实现数据的保存,下次可以将对象从文件中恢复出,只需要此对象实现了Serializable接口即可,注意的两点是,一是为对象添加static long serialVersionUID = 42L;随便指定一个数值,这是这个对象的唯一标识,即有相同标识才可以从文件中恢复出对象;二是在不需要序列化的对象前加上transient关键字。序列化只会序列化堆中的数据,静态数据不会被序列化,transient关键字的也不会。

6、管道流,PipedInputStreamPipedOutputStream,管道流就好像输入输出为一条管道,输入流可以从管道中读取数据,而输出流可以向管道中输入。可以通过两条线程同时操作,当输入流没有内容可以读取时,会柱塞线程等待输入数据。通过connect()来关联相关流。

7、RandomAccessFile用与文件的随机访问,自身具备读写方法,有rrw等打开方式,常用方法如skipBytes(int)跳过一部分内容,seek(index)将文件指针移到指定位置,适用于文件的断点写入,和多线程分段写入等。

8、ByteArrayStream是一种基于数组的流,不用close操作,也不会抛出IOException,其简单来说就是一个数组操作工具。和其类似的有CharArrayInputStream、CharArrayOutputStream针对字符数组操作的流和StringReaderStringWriter针对字符串操作的流。

时间: 2024-10-23 04:56:59

黑马程序员-Java IO流的相关文章

黑马程序员——java——IO流——将一些字符写入到指定硬盘上的目录中去:

将一些字符写入到指定硬盘上的目录中去: import java.io.*; //将一些文字储存到硬盘的文件中去 //操作的是文字,因此选用字符流来操作 public class FileWriterDemo { public static void main(String[] args) { //创建一个可以往文件中写入字符数据的字符输出流对象 //既然是往一个文件中写入文字数据,那么在创建对象时,就必须明确该文件(用于存储数据的目的地) //如果文件不存在,则会自动创建 //如果文件存在,则会

黑马程序员——java IO流

java中,IO流需要操作系统资源,使用完毕后要释放资源. IO流根据操作的数据的类型的不同,可以分为字节流和字符流, 字符流是基于字节流的. 字符流的顶层基类是Reader和Writer 字节流的顶层基类是InputStream和OutputStream 流是用来操作数据的,数据的最常见形式是文件,字符流针对的是文本文件,字节流针对的是二进制文件(如图片文件). 1.FileWriter是Writer的一个子类,创建FileWriter对象后,如果源文件不存在则创建新文件:如果源文件存在则覆盖

黑马程序员&mdash;&mdash;9 IO流

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- IO 一.概念:IO流即InputOutput的缩写,来处理设备间的数据传输 1.特点:对数据的操作通过流的方式,分为字节流和字符流输入流输出流 2.IO流的常用基类:字节流的抽象基流:InputStream和OutputStream  字符流的抽象基流:Reader和Writer 注:此四个类派生出来的子类名称都是以父类名作为子类名的后缀,以前缀为其功能:如InputStream子类File

黑马程序员——java基础---IO(input output)流字符流

黑马程序员——java基础---IO(input output)流字符流 ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- io(input output)流特点: 1,io流用来处理数据之间的传输 2,java对数据的操作是通过流的方式: 3,java用于操作流的对象都在io包中: 4,流按操作数据分为两种:字节流和字符流: 5,流按流向分为:输入流和输出流. 注意:流只能操作数据,而不能操作文件. 3.IO流的常用基类: 1)字节流的抽象

黑马程序员——Java基础---IO(下)

黑马程序员——Java基础---IO(下) ------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------ 一.概述 Java除了基本的字节流.字符流之外,还提供了File类.properties类.打印流.序列流等和输入输出相关的类,它们能够帮助我们更好的处理信息.下面将对它们进行简单的介绍. 一.正

黑马程序员——Java I/O流基础知识点(File类)

File工具 File类就是用俩将文件或者文件夹封装对象,弥补流对象的不足--流只能操作数据,不能操作文件夹的 封装的是路径!!! 构造方法演示 1.可以将已有的未出现的文件或者文件夹封装成对象. File f1=new File("c:\\abc\\a.txt"): File f2=new File("d:\\abc","ab.txt"打印,会打印路径.:目录分隔符,为了更好地跨平台File. File类常见功能 1,创建 createNewF

黑马程序员——Java I/O基础知识之I/O流

I/O流基础知识--字节流和字符流 文件存储在硬盘中,是以二进制表示的,只有内存中才能形成字符.数据的来源可以有硬盘,内存,控制台,网络,Java把数据从一个地方转到另一个地方的现象称为流,用InputStream和OutputStream接口来表示,这两个流里面的都是以字节为单位的,后来加入了Reader和Writer,里面操作的是字符,是两个字节为单位的. 字节流 字节流将数据写入文件 try { File file =new File("d:" +File .separator+

黑马程序员——Java基础---io(上)

黑马程序员——Java基础---io(上) ------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------ 一.概述 Java I/O系统负责处理程序的输入和输出,I/O类库位于java.io包中,它对各种常见的输入流和输出流进行了抽象.如果数据流中最小的数据单元是字节,那么称这种流为字节流:如果数据流

黑马程序员——I/O流基础知识

I/O流 Io流 代表有能力产生数据的数据源对象或者有能力接收对象的数据接收端对象.字节流和字符流.中文字符也转编码表,jbk2万多中文字.unicode全世界的字符收录.乱码,两种不同形式的编码表.字符流里面的对象融合了编码表,以便别人使用的使用用你指定的编码方式. 基类:读和写~ 字节流 InputStream,OutputStream 字符流 Reader,Writer Writer 主力方法是writer().既然IO流是操作数据的,而数据的最常见体现形式是:文件. 需求:准备在硬盘上创