美文网首页
Java基础之IO流

Java基础之IO流

作者: 小任务大梦想 | 来源:发表于2019-05-30 15:11 被阅读0次

什么是IO流?

 IO是指应用程序对设备数据的输入输出操作。流的本质是数据传输。例如:键盘是输入设备,而显示器则是输出设备。在Java中定义了各种各样的输入输出方式,它们都被存放在java.io包中。

IO流的分类

  • 根据处理数据类型分为:字符流和字节流,字符流操作的是16位二进制,字节流操作的是8位二进制。
  • 根据数据流向分为:输入流和输出流

IO包中类层次关系图

I层次关系图

File类

File类是IO包中唯一代表磁盘文件本身的对象。通过File来创建,删除,重命名文件,判断文件的读写权限以及文件是否存在,设置和查询文件的最近修改时间等。但File类不是InputStream、OutputStream或Reader、Writer的子类,因为它不负责数据的输入输出,而专门用来管理磁盘文件与目录。File类主要用于命名文件、查询文件属性和处理文件目录。

生成File对象的构造方法:
1)File (String directorypath)

 例:File file=new File("test.txt"); //根据路径获得相应的File对象
 相对路径:相对于某个文件的路径。
 绝对路径:一个固定的路径,具体到某个盘。

2)File(URI uri)

3)File (String parent , String child)

 例:File file=new File(“/Users/wq/Desktop/outInFile","test.txt") ;

4)File (File parent , String child)

  例: File file=new File("/Users/wq/Desktop/outInFile");
    File file1=new File(file,"test.txt"); //在如果/Users/wq/Desktop/outInFile目录不存在则需要先使用file.mkdir()先创建。

一个对应于某磁盘文件或目录的File对象一经创建, 就可以通过调用它的方法来获得文件或目录的属性。

1)boolean exists( ) 判断文件或目录是否存在
2)boolean isFile( ) 判断是文件还是目录
3)boolean isDirectory( ) 判断是文件还是目录
4)String getName( ) 返回文件名或目录名
5)String getPath( ) 返回文件或目录的路径
6)long length( ) 获取文件的长度
7)String getParent( ) 获得父文件夹名称
8)long lastModified( ) 获取文件的最后修改时间
9)String getAbsolutePath() 返回文件或目录的绝对路径
10) ......

File类中还定义了一些对文件或目录进行管理、创建、删除:

1) boolean renameTo( File newFile ); 重命名文件
2) void delete( ); 删除文件
3) boolean mkdir( ); 创建目录
4)boolean createNewFile(); 创建文件

RandomAccessFile类

  RandomAccessFile类支持随机访问,可以跳转到文件的任意位置处读写数据。当要访问一个文件时,不想把文件从头访问到尾,RandomAccessFile类就是最佳的选择。但该类仅限于操作文件啊,不能访问其他的IO设备,如网络,内存映像等。

RandomAccessFile不属于InputStream和OutputStream类。

 创建RandomAccessFile类对象的构造方法:

 RandomAccessFile(File file, String mode);
 RandomAccessFile(String name, String mode);

 mode值:
 r: 以只读方式打开指定文件 。
 rw :以读写方式打开指定文件 。
 rws: 读写方式打开,并对内容或元数据都同步写入底层存储设备 。
 rwd: 读写方式打开,对文件内容的更新同步更新至底层存储设备 。

 类对象的一些常用方法:
 1 ) void seek(long pos):将文件记录的指针定位到pos位置。
 2 )long getFilePointer( ):返回文件记录指针的当前位置,指针默认位置为0。
 3 )int skipBytes(int n):指针跳过的字节数。
 4 )void setLength(long newLength) :设置此文件的长度。
 5 )......

e.g.

package IO;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class RandomAccessFileTest {

    public static void main(String[] args) throws IOException {
        RandomAccessFile accessFile = new RandomAccessFile(new File("/Users/wq/Desktop/outInFile/test.txt"), "r");
        
//      accessFile.seek(8);//指定记录指针的位置
        
        accessFile.skipBytes(9);//跳过多少个字节
        
        System.out.println(accessFile.getFilePointer());//当前位置
        
        byte[] buff = new byte[1024];
        int len = 0;
        while ((len = accessFile.read(buff))!=-1){
            System.out.println(new String(buff,0,len));
            System.out.println(new String(buff,0,len).getBytes("UTF-8").length);//UTF-8编码长度
            
            
        }
        accessFile.close();

    }

}


运行结果:

9
候放学了
12

 文件中的内容是“这个时候放学了”,但是指针跳过了9个字节,而不同的编码格式占字节数是不同的,UTF-8编码下一个中文所占字节也是不确定的,可能是2个、3个、4个字节。由运行结果可以看出在UTF-8的编码格式下,一个汉字占了3个字节,所以最后打印出来的结果是跳了三个汉字。


 Java的输入输出流建立在4个抽象类的基础上:InputStream,OutputStream,Reader和Writer,它们无法直接创建实例。一般来说,处理字符串或者字符时应使用字符流,处理字节或二进制对象时应使用字节流。

字节流

 字节流为处理字节的输入输出提供了丰富的环境,一个字节流可以和其他任意类型的对象合并,包括二进制数据。

输入字节流(InputStream)

InputStream是字节输入模式的抽象类,该类的所有方法在出错时都会抛出IOException异常。InputStream的常用方法:

方法 描述
int read() 如果下一个字节可读,则返回一个整型,遇见文件尾时,则返回-1
int read(byte[] b) 从输入流中最多读取b.length个字节的数据,并将其存储在字节数组b中,返回实际读取的字节数,遇见文件尾时返回-1
int read(byte[] b,int off,int len) 从输入流中读取len个字符的数据,并将其存储在数组b中,从off位置开始,返回实际读取的字符数,遇见文件尾时返回-1。
void close() 关闭输入流,关闭之后如果再读取则会抛出IOException 异常
void reset() 重新设置输入指针到先前设置的标志处
void mark(int numBytes) 在输入流的当前位置放置一个标志,在该流读取numBytes 个byte前都有效
boolean markSupported() 判断输入流是否支持mark()/reset()操作,如果支持则返回true
long skip(long n) 忽略n个字节,返回实际忽略的字节
输出字节流(OutputStream)

 该类的所有方法返回一个void 值,并且在出错的情况下抛出一个IOException异常。OutputStream的常用方法:

方法 描述
void write(int b) 将指定的字节/字符输出到输出流中
void write(byte[]/char[] buf) 将字节数组/字符数组中的数据输出到指定输出流中
void write(byte[]/char[] buf, int off,int len ) 将字节数组/字符数组中从off位置开始,长度为len的字节/字符输出到输出流中
void close() 关闭输出流
void flush() 定制输出状态以使每个缓冲器都被清除,也就是刷新输出缓冲区

一般操作文件流时的步骤

  • 使用File类找到一个文件。
  • 通过File类的对象去实例化字节流或字符流的子类。
  • 进行字节流或字符流的读写操作。
  • 关闭文件流。

 下面就以文件输入输出流为例,书写例子

package IO;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileStreamTest {

    public static void main(String[] args) throws IOException {
        //文件输出流
        FileOutputStream fileOutputStream = new FileOutputStream("/Users/wq/Desktop/outInFile/test.txt");//空白文件
        //文件输入流
        FileInputStream  fileInputStream  = new FileInputStream("/Users/wq/Desktop/outInFile/test.txt");
        
        byte[] outB = "今天是个好日子".getBytes();
            fileOutputStream.write(outB);
            
            
        byte[] b = new byte[1024];//接收从输入流中读取出来的数据
        if(fileInputStream.read(b) > 0) {
            String result = new String(b);
            System.out.println(result);
        }
        
        fileInputStream.close();//关闭文件输入流
        fileOutputStream.close();//关闭文件输出流
    }

}

 在执行写入文件的时候,将“今天是个好日子”内容写入到test.txt文件中,在执行读取文件的时候将内容读取了出来。

  • FileInputStream在读取文件的时候,传入的文件路径不存在,那么在执行read方法时会报FileNotFoundException异常。
  • FileOutputStream在写入文件的时候,传入的文件路径不存在, 那么在执行write方法时, 会默认创建一个该路径下的文件并且不会报错。

字符流

 字符流提供了处理任何类型的输入输出操作功能,但是它们不能直接操作Unicode字符。其层次结构的顶层是Reader和Writer。

字符输入流(Reader)

Reader类中的常用方法:

  • int read(),int read(char[] c),abstract int read(char[] b,int off,int len),abstract void close(),long skip(long numChars)和InputStream中的方法用法相似,这里就不一一描述了。
  • Boolean ready():如果下一个输入请求不等待则返回true,否则返回false。
字符输出流(Writer)

该类的所有方法都返回void的值并且在出错的时候抛出IOException异常。
-abstract void close(),abstract void fush(), void write(int char),void write(char ch[]),abstract void write(char[] buf, int off,int len ), void write(String str),void write(String str, int off,int len )其用法和OutputStream中方法的用法相似。

e.g. FileReader/Filewrite为例

package IO;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class FileReadAndWrite {

    public static void main(String[] args) throws IOException {
        FileWriter fileWriter = new FileWriter("/Users/wq/Desktop/outInFile/test.txt");
        FileReader fileReader = new FileReader("/Users/wq/Desktop/outInFile/newtest.txt");
        
        String write = "这个时候放学了";
        fileWriter.write(write);//写入文件
        
        char[] reader = new char[1024];
        int i =fileReader.read(reader);
        if(i >0) {
            System.out.print(new String(reader,0,i));//读出文件
        }
        
        fileWriter.close();
        fileReader.close();

    }

}

几种流的使用

1)管道流

 管道流主要用于两个线程间的通信。管道流分为管道字节流(PipedInputStream,PipedOutputStream)和管道字符流(PipedReader,PipedWriter)。
e.g.

package IO;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class PipedStreamDemo {

    public static void main(String[] args) {
        try {
        Sender sender = new Sender();
        Receiver receiver = new Receiver();
        
        PipedOutputStream out = sender.getPipedOut();//写入
        PipedInputStream in = receiver.getPipedin();//读出
        out.connect(in);//将输出发送到输入
        
        Thread senderThread = new Thread(sender);
        Thread receiverThread = new Thread(receiver);
        
        senderThread.start();//启动线程
        receiverThread.start();
        
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }

}
class Sender implements Runnable{
    private PipedOutputStream pipedOut = new PipedOutputStream();

    public PipedOutputStream getPipedOut() {
        return pipedOut;
    }

    @Override
    public void run() {
        String message = "那谁,收到消息的人,你好!";
        try {
            pipedOut.write(message.getBytes());//写入内容
            pipedOut.close();//关闭流
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }
}
class Receiver implements Runnable{
    private PipedInputStream pipedin = new PipedInputStream();
    
    public PipedInputStream getPipedin() {
        return pipedin;
    }

    @Override
    public void run() {
        byte[] b = new byte[1024];
        try {
            pipedin.read(b);//读出数据
            
            String messageIn = new String(b);
            System.out.println("这是收到的信息: " +messageIn);
            pipedin.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }
}

运行结果

这是收到的信息: 那谁,收到消息的人,你好!
2 )对象流(ObjectInputStream,ObjectInputStream)

 使用对象流写入或读入对象时,要保证对象是序列化的。这是为了保证能把对象写入到文件,并能再把对象读回到程序中的缘故。一个类如果实现了Serializable接口,那么这个类创建的对象就是所谓序列化的对象。
e.g.

package IO;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class ObjectStreamDemo {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        
        FileOutputStream fileOutputStream = new FileOutputStream("/Users/wq/Desktop/outInFile/student.txt");
        
        ObjectOutputStream objectOutputStream =new ObjectOutputStream(fileOutputStream);
        Student student = new Student("琪琪", 23);
        objectOutputStream.writeObject(student);
        
        
        FileInputStream fileInputStream=new FileInputStream("/Users/wq/Desktop/outInFile/student.txt");
        ObjectInputStream objectInputStream=new ObjectInputStream(fileInputStream);
        Student tempStudent=(Student)objectInputStream.readObject();
        System.out.println("Student对象为:"+tempStudent);
        
        //关闭流
        objectInputStream.close();
        objectOutputStream.close();

    }

}

 ObjectOutputStream对象输出流在写入文件student.txt的时候,因为对象是被序列化了的,所以看不到你想让它写进去的内容,只有通过ObjectInputStream把文件读出来显示。

注意事项
 1.读取顺序和写入顺序一定要一致,不然会读取出错。
 2.保证对象是序列化的,必须实现Serializable接口。

3 )转换流

 InputStreamReader和OutputStreamWriter这两个类是字节流和字符流之间相互装转换的类,其中InputStreamReader用于讲一个字节流中的字节解码成字符,OutputStreamWriter用于将写入的字符解码成字节后写入一个字节流。
e.g.

package IO;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class BufferStream {
    
     public static void main(String[] args) throws IOException {
            InputStreamReader reader=new InputStreamReader(System.in);
           
            BufferedReader bufferedReader=new BufferedReader(reader);
            
                System.out.println("请输入 : ");
                String str = bufferedReader.readLine();//获取键盘输入的数据
                if(str != null) {
                     System.out.println("打印输入的内容 :" +str);
                }
                
                bufferedReader.close();//关闭流
    }
}

 为了达到最高效率,避免频繁的进行字符与字节之间的转换,最好使用BufferedWriter类包装OutputStreamWriter类,用BufferedReader类包装InputStreamReader类。

BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufferedWriter=new BufferedWriter(new OutputStreamWriter(System.out));

4 )打印流

 主要包含字节打印流PrintStream,字符打印流PrintWriter。PrintStream类提供了一系列的print和println方法,可以实现将基本数据类型的格式转换成字符串输出。

 PrintStream类中构造方法:
 1 ) PrintStream(OutputStream out)
 2 ) PrintStream(OutputStream out,Boolean autoflush);//autoflush遇到换行符时是否自动清空缓冲区。
 3 ) PrintStream(OutputStream out,Boolean autoflush,String econding);//econding编码方式

package IO;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class PrintStream {

    public static void main(String[] args) throws FileNotFoundException {
        
        OutputStream out = new FileOutputStream("/Users/wq/Desktop/outInFile/PrintStreamTest.txt");//将内容输出到制定文件中
        
        java.io.PrintStream printStream = new java.io.PrintStream(out);
        
        printStream.print("对面的女孩看过来");
        printStream.close();
        
    }

}

运行结果图

  PrintWriter类中构造方法:
 1 ) PrintWriter(File file);//使用指定文件创建不具有自动行刷新的新 PrintWriter
 2 ) PrintWriter(OutputStream out);
 3 ) PrintWriter(OutputStream out,boolean autoFlush);
 4 ) PrintWriter(String fileName);//创建具有指定文件名称的 PrintWriter
 5 ) PrintWriter(Writer out,boolean autoFlush);
 6 ) ......
   //autoflush遇到换行符时是否自

e.g.

package IO;

public class PrintWriter {

    public static void main(String[] args) {
        java.io.PrintWriter printWriter = new java.io.PrintWriter(System.out);
        printWriter.println("这是在屏幕上面输出的内容");
        
        printWriter.close();
    }

}

5 )合并流(SequenceInputStream)

 将两个文件合并在一起,主要操作的是内容

 合并流的操作步骤:

 1 )创建输入流
 2 )建立一个FileOutputStream实例,用于写入合并的文件的内容。
 3 )通过SequenceInputStream类,把文件的内容合并起来,放到这个类实例流中。但如果我们有超过两个输入流需要加入到合并之后,就不能直接传递输入流的引用到合并流,我们需要将输入流封装到一个枚举类型的对象中,将该对象的引用传递给合并流的构造函数
 4 )把SequenceInputStream实例的内容读取出来。

package IO;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;

public class SequenceInputStreamTest {

    public static void main(String[] args) throws IOException {
        
        FileInputStream fileInputStream1 = new FileInputStream(new File("/Users/wq/Desktop/outInFile/test.txt"));//要合并的两个文件
        FileInputStream fileInputStream2 = new FileInputStream(new File("/Users/wq/Desktop/outInFile/newtest.txt"));
        
        SequenceInputStream sequenceInputStream = new SequenceInputStream(fileInputStream2, fileInputStream1);//执行合并操作
        
        FileOutputStream mergefile = new FileOutputStream(new File("/Users/wq/Desktop/outInFile/mergefile.txt"));//合并之后的文件
     
        int len;
        while ((len = sequenceInputStream.read()) != -1) {
                mergefile.write(len);
            }
        
        
        
        FileInputStream fileInputStream=new FileInputStream(new File("/Users/wq/Desktop/outInFile/mergefile.txt"));
        byte[] b = new byte[1024];
        if(fileInputStream.read(b) > 0) {
            String result = new String(b);
            System.out.println(result);
        }
        
        
        sequenceInputStream.close();//关闭合并流
        fileInputStream2.close();//关闭输入流
        fileInputStream1.close();
        mergefile.close();//关闭输出流
        fileInputStream.close();
        
    }

}

最后输出的结果是:把test.txt,newtest.txt,中的内容合并到了mergefile.txt中

Qiqi这个时候放学了
文件合并

但是如果要合并的文件数超过了两个应该怎样进行合并呢?
  SequenceInputStream提供了合并多个文件的构造方法:
  SequenceInputStream(Enumeration<? extends InputStream> e)

Vector<InputStream> vector = new Vector<>();
vector.add(inputStream1);
vector.add(inputStream2);
vector.add(inputStream3);
//获取迭代器
Enumeration<InputStream> elements = vector.elements();
//构建合并源,把三个文件读到一起,
SequenceInputStream sis = new SequenceInputStream(elements);

package IO;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.Enumeration;
import java.util.Vector;

public class MoreSequenceInputStreamTest {

    public static void main(String[] args) throws IOException {
        FileInputStream fileInputStream1 = new FileInputStream(new File("/Users/wq/Desktop/outInFile/test.txt"));//要合并的文件
        FileInputStream fileInputStream2 = new FileInputStream(new File("/Users/wq/Desktop/outInFile/newtest.txt"));
        FileInputStream fileInputStream3 = new FileInputStream(new File("/Users/wq/Desktop/outInFile/test1.txt"));
        FileInputStream fileInputStream4 = new FileInputStream(new File("/Users/wq/Desktop/outInFile/test2.txt"));
        
        
        
        Vector<FileInputStream> fileInputStreams = new Vector<FileInputStream>();
        fileInputStreams.add(fileInputStream3);
        fileInputStreams.add(fileInputStream4);
        fileInputStreams.add(fileInputStream2);
        fileInputStreams.add(fileInputStream1);
        
         Enumeration<FileInputStream> enumeration = fileInputStreams.elements();//SequenceInputStream(Enumeration<? extends InputStream> e)用来执行多个文件合并操作
        
        SequenceInputStream sequenceInputStream = new SequenceInputStream(enumeration);
        
        FileOutputStream mergefile = new FileOutputStream(new File("/Users/wq/Desktop/outInFile/mergefile.txt"));//合并之后的文件
     
        int len;
        while ((len = sequenceInputStream.read()) != -1) {
                mergefile.write(len);
            }
        
        
        
        FileInputStream fileInputStream=new FileInputStream(new File("/Users/wq/Desktop/outInFile/mergefile.txt"));
        byte[] b = new byte[1024];
        if(fileInputStream.read(b) > 0) {
            String result = new String(b);
            System.out.println(result);
        }
        
        
        sequenceInputStream.close();//关闭合并流
        fileInputStream2.close();//关闭输入流
        fileInputStream1.close();
        mergefile.close();//关闭输出流
        fileInputStream.close();

    }

}

运行结果

SequenceInputStream —> 两个文件合并在一起,主要操作的是内容 —> 例如:Qiqi这个时候放学了

代码以及概念描述有问题的地方请及时指正

相关文章

  • Java之IO流详解

    title: Java之IO流详解tags: Java IO流categories: Java IO流 大多数应用...

  • Java基础之IO流

    ##Java基础之IO流IO流常用几个类的关系如下: 字节流 字节输入流FileInputStream 读取文件用...

  • java IO入门笔记

    1.java IO流的概念,分类,类图 1.1. java IO 流的概念 java的io是实现输入和输出的基础,...

  • Java IO详解

    1 Java IO流的概念,分类 1.1 Java IO流的概念 java的IO是实现输入和输出的基础,可以方便的...

  • Java基础之IO流

    Java基础之IO流 简单介绍Java中有两种IO流,第一种是以Steam结尾的字节流,第二种是以Writer或者...

  • java基础之IO流

    IO流上:概述、字符流、缓冲区(java基础) IO流结构图 FilterInputStream、FilterOu...

  • Java基础之IO流

    流就是当不同的介质之间有数据交互的时候,JAVA就使用流来实现。数据源可以是文件,还可以是数据库,网络甚至是其他的...

  • JAVA之IO流基础

    1.A:IO技术概述 * a: Output 把内存中的数据存储到持久化设备上这个动作称为输出(写)Out...

  • Java基础之IO流

    1.IO流 Java中有几种类型的流 答:字节流,字符流。字节流继承于InputStream、OutputStre...

  • Java基础之IO流

    什么是IO流?  IO是指应用程序对设备数据的输入输出操作。流的本质是数据传输。例如:键盘是输入设备,而显示器则是...

网友评论

      本文标题:Java基础之IO流

      本文链接:https://www.haomeiwen.com/subject/ntresftx.html