IO流.专业流yu编码表

本文详细介绍了Java IO包中流对象的功能和使用方法,包括打印流PrintStream、字符流PrintWriter、序列流SequenceInputStream、管道流PipedOutputStream和PipedInputStream、内存流ByteArrayInputStream和ByteArrayOutputStream,以及编码表和流与编码的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以下介绍IO包中扩展功能的流对象:基本都是装饰设计模式。

Java.io.outputstream.PrintStream打印流

1:提供了更多的功能,比如打印方法。可以直接打印任意类型的数据。

2:它有一个自动刷新机制,创建该对象,指定参数,对于指定方法可以自动刷新。

3:它使用的本机默认的字符编码.

4:该流的print方法不抛出IOException。

 

构造函数。

PrintStream(File file)  :创建具有指定文件且不带自动行刷新的新打印流。

PrintStream(File file, String csn) :创建具有指定文件名称和字符集且不带自动行刷新的新打印流。

PrintStream(OutputStream out) :创建新的打印流。

PrintStream(OutputStream out, boolean autoFlush) :创建新的打印流。

PrintStream(OutputStream out, boolean autoFlush, Stringencoding) :创建新的打印流。

PrintStream(String fileName) :创建具有指定文件名称且不带自动行刷新的新打印流。

PrintStream(String fileName, String csn)

 只有输出目的为 流的时候 才能够设置 是否自动刷新 操作文件 则没有设置自动刷新需要手动刷新

其println()的有功能是 在字符串后面加上换行符号  (能够与Buffered的readLine()方法相呼应,TCP传输的细节)

PrintStream可以操作目的:1:File对象。2:字符串路径。3:字节输出流。

前两个都JDK1.5版本才出现。而且在操作文本文件时,可指定字符编码了。

 

当目的是一个字节输出流时,如果使用的println方法,可以在printStream对象上加入一个true参数。这样对于println方法可以进行自动的刷新,而不是等待缓冲区满了再刷新。最终print方法都将具体的数据转成字符串,而且都对IO异常进行了内部处理。

--------------------------------------------------------

PrintWriter:是字符流的子类,可以直接操作字符数据,同时也可以指定具体的编码。具备了PrintStream的特点同时,还有自身特点:

该对象的目的地有四个:1:File对象。2:字符串路径。3:字节输出流。4:字符输出流。

 只有输出目的为 流的时候 才能够设置 是否自动刷新 操作文件 则没有设置自动刷新需要手动刷新

建议:开发时尽量使用PrintWriter

 

构造方法中(目的)直接操作文件的第二参数是编码表。

(目的)直接操作输出流的,第二参数是自动刷新。

 

//读取键盘录入将数据转成大写显示在控制台.

BufferedReader bufr = new BufferedReader(newInputStreamReader(System.in));//源:键盘输入

//目的:把数据写到文件中,还想自动刷新。

PrintWriter out = new PrintWriter(new FileWriter("out.txt"),true);//设置true后自动刷新

String line = null;
while((line=bufr.readLine())!=null){
    if("over".equals(line))
        break;
    out.println(line.toUpperCase());//转大写输出
}
    //注意:System.in,System.out这两个标准的输入输出流,在jvm启动时已经存在了。随时可以使用。当jvm结束了,这两个流就结束了。但是,当使用了显示的close方法关闭时,这两个流在提前结束了。
out.close();
bufr.close();

**********************************************************************************************************************

SequenceInputStream:序列流,作用就是将多个读取流合并成一个读取流。实现数据合并。

表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止,并 补上文件结束的标致。

这样做,可以更方便的操作多个读取流,其实这个序列流内部会有一个有序的集合容器,用于存储多个读取流对象。

构造方法

SequenceInputStream(InputStream s1,InputStream s2) 和并两个输入流为一 最简单 

SequenceInputStream(Enumeration<? extendsInputStream> e)  哟要合并两个以上流 涉及到集合枚举

该对象的构造函数参数是枚举,想要获取枚举,需要有Vector集合,但不高效。需用ArrayList,但ArrayList中没有枚举,只有自己去创建枚举对象。

但是方法怎么实现呢?因为枚举操作的是具体集合中的元素,所以无法具体实现,但是枚举和迭代器是功能一样的,所以,可以用迭代替代枚举。

 

ArrayList<FileInputStream> a = new ArrayList<FileInputStream>();
		for (int i = 0; i < parts; i++) {
			fis = new FileInputStream(new File(path,(i+1)+".part"));
			System.out.println(i);
			a.add(fis);
		}
		final Iterator it = a.iterator();//变量it在局部位置的内部类被访问 所以it必须为final
		//Enumeration e = Collections.enumeration(a);  测试过不可以呀
		Enumeration e = new Enumeration(){
			@Override
			public boolean hasMoreElements() {
				// TODO Auto-generated method stub
				return it.hasNext();
			}
			@Override
			public Object nextElement() {
				// TODO Auto-generated method stub
				return it.next();
			}};
		SequenceInputStream ss = new SequenceInputStream(e);
		FileOutputStream fos =  new FileOutputStream(un);
		byte[] buf = new byte[1024*1024];
		int len = 0;
		while ((len=ss.read(buf))!=-1) {
			fos.write(buf, 0, len);
			fos.flush();
		}

合并原理:多个读取流对应一个输出流。

切割原理:一个读取流对应多个输出流。

点击打开链接

切割大文件

FileInputStream fis = new FileInputStream("E:/1998.rmvb");
		FileOutputStream fos = new FileOutputStream("E:/1.part");
		byte[] by = new byte[1024*1024];//创建一个存储大小为1M 的字节数组
		int len = 0;
		int count=1;
		int i=0;
		while ((len = fis.read(by))!=-1)
		{	
			i++;
			if(i==101)
			{
				count++;
				fos = new FileOutputStream("E:/"+count+".part");
				i=0;
			}
				
			fos.write(by,0,len);//字节数组内有多少 写多少  字节流不需要刷新即可把数据写入目标文件
		}
		fos.close();//养成关流的好习惯
		fis.close();

类 ObjectOutputStream   实现了DataInput接口 能够写如完整的基本数据

 注意被写入的对象需要实现Serializable

    构造方法

        ObjectOutputStream(OutputStreamout)  不可直接操作文件 FileInputStream是专门操作文件的字节流

          创建写入指定OutputStream 的 ObjectOutputStream。

    常用方法

         void write(int val)  写入一个字节。

         void writeInt(int val) 写入一个 32 位的 int 值。

         void writeObject(Object obj) 将指定的对象写入ObjectOutputStream。

类 ObjectInputStream

    构造方法

        ObjectInputStream(InputStreamin)

          创建从指定InputStream 读取的 ObjectInputStream。

    常用方法

         int readInt() 读取一个 32 位的 int 值。

         int read() 读取数据字节。

         Object readObject() 从ObjectInputStream 读取对象。

ObjectOutputStream存的文件 只能用ObjectInputStream来读取

对象的序列化:目的:将一个具体的对象进行持久化,写入到硬盘上。

Serializable:给类定义标记,用于启动对象的序列化功能,可以强制让指定类具备序列化功能,该接口中没有成员,这是一个标记接口。这个标记接口用于给序列化类提供UID。这个uid是依据类中的成员的数字签名进行运行获取的,成员变动则UID变化。如果不需要自动获取一个uid,可以在类中,手动指定一个名称为serialVersionUID id号,static final longserialVersionUID = 42L; 依据编译器的不同,或者对信息的高度敏感性。最好每一个序列化的类都进行手动显示的UID的指定。

注意静态数据不能被序列化,因为静态数据不在堆内存中,是存储在静态方法区中,无法被序列化存到文件。

如何将非静态的数据不进行序列化transient关键字修饰此变量即可。

****************************************************************************************************

RandomAccessFile:  直接继承Object 实现DataInput,DataOutput能够读和写 能操作基本数据类型

特点:

1:该对象即可读取,又可写入。

2:该对象中的定义了一个大型的byte数组,通过定义指针来操作这个数组。

3:可以通过该对象的getFilePointer()获取指针的位置,通过seek()方法设置指针的位置。

4:该对象操作的源和目的必须是文件

5:其实该对象内部封装了字节读取流和字节写入流。

注意:实现随机访问,最好是数据有规律。该类不算是IO体系中的子类,而是直接继承自Object但是它是IO包中的成员,因为它具备读和写功能,内部封装了一个数组,而且通过指针对数组的元素进行操作,其实完成读写的原理就是内部封装了字节输入流和输出流。

构造方法

      RandomAccessFile(File file, String mode)

          创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。

RandomAccessFile(String name, String mode)

          创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。

通过构造函数可看出 该类只能操作文件, 而且操作文件还有模式:只读r 读写 rw

如果模式为只读 r ,不会创建文件。会去读取一个已存在的文件,如果该文件不存在,则会出现异常

如果模式为 rw的话,当操作的文件不存在,会自动创建,如果存在不会覆盖

常用方法

        long length()  返回此文件的长度。

        int read()  从此文件中读取一个数据字节。

        int read(byte[] b,int off, int len)   将最多 len 个数据字节从此文件读入 byte 数组。

        int read(byte[] b,int off, int len)  将最多 len 个数据字节从此文件读入 byte 数组。

        读取基本数据类型  readByte()  readChar() readFloat()  readDouble()  readBoolean()

        String readLine()   从此文件读取文本的下一行。

        void seek(longpos)  此文件开头开始测量的指针偏移量,在该位置发生下一个读取或写入操作。

        int skipBytes(intn)    尝试跳过输入的 n 个字节以丢弃跳过的字节。

        void write(byte[]b)  将 b.length 个字节从指定 byte 数组写入到此文件,并从当前文件指针开始。

        void write(int b)  向此文件写入低8位的int。

void writeInt(intv)  按四个字节将 int 写入该文件,先写高字节。

void writeLong(longv)  按八个字节将 long 写入该文件,先写高字节。

********************************************************************************************

管道流:管道读取流和管道写入流可以像管道一样对接上,管道读取流就可以读取管道写入流写入的数据。

注意:需要加入多线程技术,因为单线程,先执行read,会发生死锁,而read方法是阻塞式的,没有数据的read方法会让线程等待。

类 PipedOutputStream

    构造方法

        PipedOutputStream(PipedInputStreamsnk)  创建连接到指定管道输入流的管道输出流。

    常用方法

PipedOutputStream(PipedInputStreamsnk)  创建连接到指定管道输入流的管道输出流。

        voidwrite(int b)        将指定 byte 写入传送的输出流。

类 PipedInputStream

        PipedInputStream()  创建尚未连接的 PipedInputStream。

        PipedInputStream(PipedOutputStreamsrc)  创建 PipedInputStream,使其连接到管道输出流 src。

        PipedInputStream(PipedOutputStreamsrc, int pipeSize)

          创建一个PipedInputStream,使其连接到管道输出流 src,并对管道缓冲区使用指定的管道大小。

常用方法

        voidconnect(PipedOutputStream src)      使此管道输入流连接到管道输出流 src。

        int read()  读取此管道输入流中的下一个数据字节。

        int read(byte[] b,int off, int len)  将最多 len 个数据字节从此管道输入流读入 byte 数组。

        protected  void receive(int b)  接收数据字节。

 

**************************************************************************

ByteArrayInputStream源:内存  在构造的时候,需要接收数据源,而且数据源是内存中的一个字节数组

ByteArrayOutputStream目的:内存在构造的时候不要定义数据目的,因为该对象中已经内部封装了可变长度的字节数组,这就是数据目的地。

这两个流对象不涉及底层资源调用,操作的都是内存中数组,并没有使用系统资源,所以不需要close关闭。

 ByteArrayOutputStream 主要方法

        voidwriteTo(OutputStream out)

          将此 byte 数组输出流的全部内容写入到指定的输出流参数中。

        String toString()

          使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。

        int size()   返回缓冲区的当前大小。


直接操作字节数组就可以了,为什么还要把数组封装到流对象中呢?因为数组本身没有方法,只有一个length属性。为了便于数组的操作,将数组进行封装,对外提供方法操作数组中的元素。

对于数组元素操作无非两种操作:设置(写)和获取(读),而这两操作正好对应流的读写操作。这两个对象就是使用了流的读写思想来操作数组。

//创建源:

    ByteArrayInputStreambis = new ByteArrayInputStream("abcdef".getBytes());

    //创建目的:

    ByteArrayOutputStreambos = new ByteArrayOutputStream();

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

编码表

常见的编码表

ASCII:美国标准信息交换码。

用一个字节的7位可以表示。

ISO8859-1:拉丁码表。欧洲码表

用一个字节的8位表示。

GB2312:中国的中文编码表6000多字。两字节表示而且两字节的高位都是1兼容ASCII

GBK:中国的中文编码表升级,融合了更多的中文文字符号,一中文两字节。两万多

Unicode:国际标准码,融合了多种文字。

所有文字都用两个字节来表示,Java语言使用的就是unicode

UTF-8:最多用三个字节来表示一个字符。

 

在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成。

程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。


你好  utf-8 >>>  gbk      浣犲ソ

         gbk   >>>  utf-8   ???

可以用来判断编码是utf-8还是gbk

 

String s = "";

              byte[]b = s.getBytes();

              for(int i = 0; i < b.length; i++) {

                     System.out.print(b[i]+",");

输出:-57,-82,-47,-89,-55,-83,

中文用两字节表示而且两字节的高位都是1即都是负数

 

字符流能不能用于对图片的操作,是不可以的。

原因  用字符流赋值图片的话 有可能无法打开 因为 字符流按默认编码表读取数据字符流读两字节数据(单字符)就会去查编码表返回中文字符 如果能查到编码表

对应的中文字符 那么读取的两字节数据不会变(编码不变) 如果查不到 那么就会去未知数据区域查编码会改变所读取的编码 那么数据就可能会产生变化

字节流 + 字符编码 = 字符流

  字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好!如果是音频文件、图片、歌曲,就用字节流好点,如果是关系到中文(文本)的,用字符流好点 
     所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取以形成字节序列 


//为什么你好 gbk -> 编码 -> iso8859-1 ->解码 =乱码 -> iso8859-1 -> 编码 -> gbk ->解码 =你好

//     你好 utf-8 -> 编码 -> iso8859-1 ->解码 =乱码 -> iso8859-1 -> 编码 -> utf-8 ->解码 =你好

//     你好 utf-8 -> 编码 -> gbk ->解码 =乱码 -> gbk -> 编码 -> utf-8 ->解码 =你好

//不可以??  你好 gbk -> 编码 -> utf-8 ->解码 =乱码 -> utf-8 -> 编码 -> gbk ->解码 = 乱码

 

 

原数据 编码存入文件(文件中的是编码后数据)  读取通过对照同一编码表 读取 还原数据

原数据 编码存入文件(文件中的是编码后数据)  读取通过对照另一个编码表 读取 当遇到的编码字节数据 找不到对应的符号 那么就会 拿着编码 去 未知字符区查找 字符 得出二进制数据 原数据改变

 

原二进制数据 通过编码表转码 的到编码数据 gbk两字节二进制数据 转码为 两字节编码数据   utf-8 三字节原二进制数据 通过utf-8编码表 转码为三字节编码数据

 

在 Java 中,“字符串”与“字节串”之间可以方便地按照指定编码规则进行转化:

byte[] b = "中文123".getBytes("GB2312");// 从字符串按照 GB2312 得到字节串

System.out.println(b.length); // 得到长度为7个 (D6,D0,CE,C4,31,32,33)

Stringstr = newString(b,"GB2312");// 从字节串按照 GB2312 得到字符串

System.out.println("中文123".length()); // 得到长度为5,因为是5个字符

 

在 java.io.* 包里面有很多类,其中,以“Stream”结尾的类都是用来操作“字节串”的类,以“Reader”,“Writer”结尾的类都是用来操作“字符串”的类。任何一个文件保存到硬盘上的时候,都是以字节为单位保存的,当要把“字符串”保存到硬盘上的文本文件,必然要选择一种编码。

有两种方法来指定编码:

Stringstr = "中文123";

// 第一种办法:先用指定编码转化成字节串,然后用 Stream 类写入

OutputStream os =newFileOutputStream("1.txt");

byte[] b = str.getBytes("utf-8");

os.write(b);

os.close();

// 第二种办法:构造指定编码的 Writer 来写入字符串

Writer ow=newOutputStreamWriter(newFileOutputStream("2.txt"),"utf-8");

ow.write(str);

ow.close();

// 最后得到的 1.txt 和 2.txt 都是 9 个字节。(汉字在 utf-8编码规则中占3字节

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值