java的各种输出流_Java基础之IO流

什么是IO流?

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

IO流的分类

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

根据数据流向分为:输入流和输出流

IO包中类层次关系图

8c532b565df5

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();

}

}

8c532b565df5

运行结果图

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这个时候放学了

8c532b565df5

文件合并

但是如果要合并的文件数超过了两个应该怎样进行合并呢?

SequenceInputStream提供了合并多个文件的构造方法:

SequenceInputStream(Enumeration extends InputStream> e)

Vector vector = new Vector<>();

vector.add(inputStream1);

vector.add(inputStream2);

vector.add(inputStream3);

//获取迭代器

Enumeration 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 fileInputStreams = new Vector();

fileInputStreams.add(fileInputStream3);

fileInputStreams.add(fileInputStream4);

fileInputStreams.add(fileInputStream2);

fileInputStreams.add(fileInputStream1);

Enumeration 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这个时候放学了

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值