Java中的IO流(一)字节流的常用操作

Tricia ·
更新时间:2024-11-14
· 954 次阅读

文章目录前言基础概念IO流分类导向图何为输入流和输出流?各种字节流的用法①节点流②处理流③流的使用一般步骤④流的关闭具体用法Ⅰ文件流Ⅱ字节数组流Ⅲ缓冲流Ⅳ转换流Ⅴ数据流Ⅵ对象流(序列化和反序列化)Ⅶ打印流(PrintStream)Ⅷ附加:随机访问流最后 前言

今天带来的是JAVA的IO流中的字节流,InputStream和OutputStram子类流的用法。

基础概念

流是一种抽象概念,它代表了数据的无结构化传递。按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列。从流中取得数据的操作称为提取操作,而向流中添加数据的操作称为插入操作。用来进行输入输出操作的流就称为IO流。换句话说,IO流就是以流的方式进行输入输出。

IO流分类导向图

IO分类导向图

何为输入流和输出流?

其实输入(InputStream,Reader)和输出(OutputStream,Writer)是相对于程序来讲,例如一个文件的数据要想在程序中被操作,那么就得输入到程序,这就是输入,操作完成之后又想保存到文件里面,从程序输出数据到文件的过程就是输出。

各种字节流的用法 ①节点流

概念:可以从或向一个特定的地方(节点)读写数据。

文 件 FileInputStream,FileOutputStream 文件进行处理的节点流。 数 组 ByteArrayInputStream,ByteArrayOutputStream 将数据与字节数组的互转的节点流。 ②处理流

概念:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader.处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接

缓冲流(装饰流,装饰模式的其中之一):BufferedInputStream,BufferedOutputStream —增加缓冲功能,避免频繁读写硬盘。 转换流:InputStreamReader, OutputStreamReader实现字节流和字符流之间的转换。 数据流:DataInputStream, DataOutputStream 提供将基础数据类型写入到文件中,或者读取出来. 对象流:ObjectInputStream, ObjectOutputStream对象流可以将一个对象写出,或者读取一个对象到程序中,也就是执行了序列化和反序列化的操作。

序列化的概念:
将一个对象存放到某种类型的永久存储器上称为保持。如果一个对象可以被存放到磁盘或磁带上,或者可以发送到另外一台机器并存放到存储器或磁盘上,那么这个对象就被称为可保持的。(在Java中,序列化、持久化、串行化是一个概念。)

③流的使用一般步骤 选择源,即是选择要操作的文件或者数据。 选择流,想要实现何种流的操作。 流的操作。 释放资源。 ④流的关闭

遵循先开后闭的原则,有多种流的使用时,最先创建的流对象最后关闭。(字节数组流可以不用关闭)

流的对象的创建 try{ 流的操作 }catch (IOException e) { 异常处理 }finally{ 流的释放 }

Java7提供了try-with-resources机制,其类似Python中的with语句,将实现了 java.lang.AutoCloseable 接口的资源定义在 try 后面的小括号中,不管 try 块是正常结束还是异常结束,这个资源都会被自动关闭。 try 小括号里面的部分称为 try-with-resources 块。

try(流对象的创建){ 流的操作 }catch (IOException e) { 异常处理 } 具体用法 Ⅰ文件流

将文件abc1.txt的copy到abc2.txt

InputStream is = null; OutputStream os = null; try { InputStream is = new FileInputStream("abc1.txt");//参数可以为File对象 OutputStream os = new FileOutputStream("abc2.txt");//参数可以为File对象 byte[] flush = new byte[1024]; //缓冲容器 int len = -1; //接收长度 while((len=is.read(flush))!=-1) { os.write(flush,0,len); //分段写出 } } catch (IOException e) { e.printStackTrace(); }finally{ //先开后闭 try { if (null != os) { os.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(null!=is) { is.close(); } } catch (IOException e) { e.printStackTrace(); } } Ⅱ字节数组流

简单demo将图片用字节数组流和文件流进行复制。

public class Test { public static void main(String[] args) { byte[] datas = fileToByteArray("p.png"); System.out.println(datas.length); byteArrayToFile(datas,"p-byte.png"); } /** * 1、图片读取到字节数组 * 1)、图片到程序 FileInputStream * 2)、程序到字节数组 ByteArrayOutputStream */ public static byte[] fileToByteArray(String filePath) { //1、创建源 File src = new File(filePath); byte[] dest =null; //2、选择流 InputStream is =null; ByteArrayOutputStream baos =null; try { is =new FileInputStream(src); baos = new ByteArrayOutputStream(); //3、操作 (分段读取) byte[] flush = new byte[1024*10]; //缓冲容器 int len = -1; //接收长度 while((len=is.read(flush))!=-1) { baos.write(flush,0,len); //写出到字节数组中 } baos.flush(); return baos.toByteArray(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { //4、释放资源 try { if(null!=is) { is.close(); } } catch (IOException e) { e.printStackTrace(); } } return null; } /** * 2、字节数组写出到图片 * 1)、字节数组到程序 ByteArrayInputStream * 2)、程序到文件 FileOutputStream */ public static void byteArrayToFile(byte[] src,String filePath) { //1、创建源 File dest = new File(filePath); //2、选择流 InputStream is =null; OutputStream os =null; try { is =new ByteArrayInputStream(src); os = new FileOutputStream(dest); //3、操作 (分段读取) byte[] flush = new byte[1024]; //缓冲容器 int len = -1; //接收长度 while((len=is.read(flush))!=-1) { os.write(flush,0,len); //写出到文件 } os.flush(); //防止文件太小,都存在缓冲容器里面,刷新一下 } catch (IOException e) { e.printStackTrace(); }finally { //4、释放资源 try { if (null != os) { os.close(); } } catch (Exception e) { e.printStackTrace(); } } } } Ⅲ缓冲流

装饰流指不直接连接数据源,而是以其它流对象(实体流对象或装饰流对象)为基础建立的流类,该类流实现了将实体流中的数据进行转换,增强流对象的读写能力,比较常用的有BufferedInputStream/BufferedOutputStream和BufferedReader/BufferedWriter等,装饰流类不可以单独使用,必须配合实体流或装饰流进行使用。作用:可以一定限度加快读写速度。

输入流例子:

InputStream is = new FileInputStream(File对象或者文件Path);//当然实例化可以是别的流的对象。 BufferedInputStream bis = new BufferedInputStream(is); ----------------------------------------------------------------- //装饰模式的写法 ~~俄罗斯套娃?~~ BufferedInputStream bis = new BufferedInputStream(FileInputStream(File对象或者文件Path));

输出流例子:

OutputStream os = new FileOutputStream(File对象或者文件Path);//当然实例化可以是别的流的对象。 BufferedOutputStream bos = new BufferedOutputStream(os); ----------------------------------------------------------------- //装饰模式的写法 ~~俄罗斯套娃?~~ BufferedOutputStream bos = new BufferedOutputStream(FileOutputStream(File对象或者文件Path)); Ⅳ转换流

作用:实现字节流和字符流之间的转换。
1、OutputStreamWriter,将字节输出流转换为字符输出流。

API方法:
1、flush():刷新该流的缓冲
2、close():关闭此流,关闭前需要刷新
3、getEncoding():获取此流使用的字符编码的名称。
4、write():write(char[] ,int offset,int length),写入字符数组的某一部分
write(String ,int offset ,int length),写入字符串的某一部分 write(String ),写入单个字符。

2、InputStreamReader,将字节输入流转换为字符输入流。

API方法:
1、close():关闭此流
2、getEncoding():获取此流使用的字符编码的名称
3、ready():判断此流是否已经准备好用于读取
4、read():read(),读取单个字符。
read(char[],int offset ,int length),将字符读入数组的某一部分。

public class ConvertTest { public static void main(String[] args) { //操作System.in 和System.out try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter writer =new BufferedWriter(new OutputStreamWriter(System.out));){ //循环获取键盘的输入(exit退出),输出此内容 String msg =""; while(!msg.equals("exit")) { msg = reader.readLine(); //循环读取 writer.write(msg); //循环写出 writer.newLine(); writer.flush(); //强制刷新 } }catch(IOException e) { System.out.println("操作异常"); } } } Ⅴ数据流

DataOutputStream的API方法:
1.void writeByte(int v)
将一个 byte 值以 1-byte 值形式写出到基础输出流中。
2 void writeShort(int v)
将一个 short 值以 2-byte 值形式写入基础输出流中,先写入高字节。
3 void writeInt(int v)
将一个 int 值以 4-byte 值形式写入基础输出流中,先写入高字节。
4 void writeLong(long v)
将一个 long 值以 8-byte 值形式写入基础输出流中,先写入高字节。
5 void writeFloat(float v)
使用 Float 类中的 floatToIntBits 方法将 float 参数转换为一个 int 值,
然后将该 int 值以 4-byte 值形式写入基础输出流中,先写入高字节。
6 void writeDouble(double v)
使用 Double 类中的 doubleToLongBits 方法将 double 参数转换为一个 long 值,
然后将该 long 值以 8-byte 值形式写入基础输出流中,先写入高字节。
7 void writeChar(int v)
将一个 char 值以 2-byte 值形式写入基础输出流中,先写入高字节。
8 void writeBoolean(boolean v)
将一个 boolean 值以 1-byte 值形式写入基础输出流。
9 void flush()
//清空此数据输出流。写入文件
10 int size()
//返回计数器 written 的当前值,即到目前为止写入此数据输出流的字节数。

1 byte readByte() ;//读取并返回一个输入字节。该字节被看作是 -128 到 127(包含)范围内的一个有符号值。
2 int readInt() ;//读取四个输入字节并返回一个 int 值。
3 short readShort() ;//参见 DataInput 的 readShort 方法的常规协定。
4 long readLong() ;//读取八个输入字节并返回一个 long 值。
5 float readFloat() ;//读取四个输入字节并返回一个 float 值。
6 double readDouble() ;//读取八个输入字节并返回一个 double 值。实现这一点的方法是:
先使用与 readlong 方法完全相同的方式构造一个 long 值,
然后使用与 Double.longBitsToDouble 方法完全相同的方式将此 long 值转换成一个 double 值。
7 boolean readBoolean() ;//读取一个输入字节,如果该字节不是零,则返回 true,如果是零,则返回 false。
8 char readChar() ;//读取两个输入字节并返回一个 char 值
9 String readUTF();//读入一个已使用 UTF-8 修改版格式编码的字符串

public class DataTest { public static void main(String[] args) throws IOException { //写出 ByteArrayOutputStream baos =new ByteArrayOutputStream(); DataOutputStream dos =new DataOutputStream(new BufferedOutputStream(baos)); //操作数据类型 +数据 dos.writeUTF("Himit_ZH"); dos.writeInt(520); dos.writeBoolean(false); dos.writeChar('q'); dos.flush(); byte[] datas =baos.toByteArray(); System.out.println(datas.length); //读取 DataInputStream dis =new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(datas))); //顺序与写出一致 String msg = dis.readUTF(); int age = dis.readInt(); boolean flag = dis.readBoolean(); char ch = dis.readChar(); System.out.println(flag); } } Ⅵ对象流(序列化和反序列化)

对象流将一个序列化的对象保存到硬盘中,或者硬盘中读取一个对象。对象流的存储和读取包含以下几点内容:

1、所保存的对象必须实现Serializable接口。

2、 所保存的对象的属性也必须实现Serializable接口。

3、 最好要给该对象提供一个版本号,private static final long serialVersionId。

public class ObjectTest { public static void main(String[] args) throws IOException, ClassNotFoundException { //写出 -->序列化 ByteArrayOutputStream baos =new ByteArrayOutputStream(); ObjectOutputStream oos =new ObjectOutputStream(new BufferedOutputStream(baos)); //操作数据类型 +数据 oos.writeUTF("Himit_ZH真帅"); oos.writeInt(520); oos.writeBoolean(false); oos.writeChar('a'); //对象 oos.writeObject("Python是最好用的"); oos.writeObject(new Date()); Employee emp =new Employee("马云",400); oos.writeObject(emp); oos.flush(); oos.close(); byte[] datas =baos.toByteArray(); System.out.println(datas.length); //读取 -->反序列化 ObjectInputStream ois =new ObjectInputStream(new BufferedInputStream(new ByteArrayInputStream(datas))); //顺序与写出一致 String msg = ois.readUTF(); int age = ois.readInt(); boolean flag = ois.readBoolean(); char ch = ois.readChar(); System.out.println(flag); //对象的数据还原 Object str = ois.readObject(); Object date = ois.readObject(); Object employee = ois.readObject(); //对应类型进行转型 if(str instanceof String) { String strObj = (String) str; System.out.println(strObj); } if(date instanceof Date) { Date dateObj = (Date) date; System.out.println(dateObj); } if(employee instanceof Employee) { Employee empObj = (Employee) employee; System.out.println(empObj.getName()+"-->"+empObj.getSalary()); } ois.close(); } } //javabean 封装数据 class Employee implements java.io.Serializable{ //必须实现Serializable接口才能序列化 private transient String name; //transient 该数据不需要序列化 private double salary; public Employee() { } public Employee(String name, double salary) { this.name = name; this.salary = salary; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } } Ⅶ打印流(PrintStream)

类的继承:

java.lang.Object |-java.io.OutputStream |-java.io.FilterOutputStream |-java.io.PrintStream

PrintStream 是用来装饰其它输出流。它能为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
与其他输出流不同,PrintStream 永远不会抛出 IOException;它产生的IOException会被自身的函数所捕获并设置错误标记, 用户可以通过 checkError() 返回错误标记,从而查看PrintStream内部是否产生了IOException。
另外,PrintStream 提供了自动flush 和 字符集设置功能。所谓自动flush,就是往PrintStream写入的数据会立刻调用flush()函数。

API方法:
PrintStream​(File file) 使用指定的文件创建没有自动行刷新的新打印流。
PrintStream​(File file, String csn) 使用指定的文件和字符集创建一个没有自动行刷新的新打印流。
PrintStream​(File file, Charset charset) 使用指定的文件和字符集创建一个没有自动行刷新的新打印流。
PrintStream​(OutputStream out) 创建新的打印流。
PrintStream​(OutputStream out, boolean autoFlush) 创建新的打印流。
PrintStream​(OutputStream out, boolean autoFlush, String encoding) 创建新的打印流。
PrintStream​(OutputStream out, boolean autoFlush, Charset charset) 创建一个新的打印流,具有指定的OutputStream,自动行刷新和字符集。
PrintStream​(String fileName) 使用指定的文件名创建没有自动行刷新的新打印流。
PrintStream​(String fileName, String csn) 使用指定的文件名和字符集创建一个没有自动行刷新的新打印流。
PrintStream​(String fileName, Charset charset) 使用指定的文件名和字符集创建一个没有自动行刷新的新打印流。
PrintStream append​(char c) 将指定的字符追加到此输出流。
void close() 关闭流。
void flush() 刷新流。

public class Demo { public static void main(String[] args) throws Exception {// 此处直接抛出错误 PrintStream ps = new PrintStream(new FileOutputStream(文件path或者File对象)); //写出到对应文件,基本数据类型,String.. ps.println("Himit_ZH"); ps.print('c'); ps.println(11.6 + 11.89); //多了换行 ps.print(10 + 30); ps.write(byte[] buffer, int offset, int length); ps.flush(); ps.close(); } } Ⅷ附加:随机访问流

RandomAccessFile类:是Object的子类,此类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过 getFilePointer 方法读取,并通过 seek 方法设置。

用途:例如迅雷的下载资源是随机下载资源的各个部分,而不是从头到尾。有些视频下载也是随机资源块下载。

public class RandTest { public static void main(String[] args) throws IOException { //分多少块 File src = new File("p.png"); //总长度 long len = src.length(); //每块大小 int blockSize =1024; //块数: 多少块 int size =(int) Math.ceil(len*1.0/blockSize); System.out.println(size); //起始位置和实际大小 int beginPos = 0; int actualSize = (int)(blockSize>len?len:blockSize); for(int i=0;i"+beginPos +"-->"+actualSize); split(i,beginPos,actualSize); } } /** * 指定第i块的起始位置 和实际长度 * @param i * @param beginPos * @param actualSize * @throws IOException */ public static void split(int i,int beginPos,int actualSize ) throws IOException { RandomAccessFile raf =new RandomAccessFile(new File("p.png"),"r"); RandomAccessFile raf2 =new RandomAccessFile(new File("dest/"+i+"p.png"),"rw"); //随机读取 raf.seek(beginPos); //读取 //3、操作 (分段读取) byte[] flush = new byte[1024]; //缓冲容器 int len = -1; //接收长度 while((len=raf.read(flush))!=-1) { if(actualSize>len) { //获取本次读取的所有内容 raf2.write(flush, 0, len); actualSize -=len; }else { raf2.write(flush, 0, actualSize); break; } } raf2.close(); raf.close(); } } 最后

其它博文:Java中的IO流(二)字符流的常用操作


作者:Himit_ZH



io 字节流 io流 JAVA

需要 登录 后方可回复, 如果你还没有账号请 注册新账号
相关文章