1JAVA.IO字节流inputstream.pngLineNumberInputStream和StringBufferInputStream官方已经不推荐使用了。推荐使用LineNumberReader和StringReader而不是ByteArrayInputStream和ByteArrayOutputStream字节数组处理流,在内存中创建缓冲区作为流使用。从缓冲区读取数据比从存储介质(如磁盘)读取数据更快//使用ByteArrayOutputStream临时缓存其他通道的数据ByteArrayOutputStreamdata=newByteArrayOutputStream(1024);//1024字节大小的缓冲区data.write(System.in.read());//暂时存储用户输入数据//将数据转换为ByteArrayInputStreamByteArrayInputStreamin=newByteArrayInputStream(data.toByteArray());FileInputStream和FileOutputStream访问文件,将文件作为InputStream,实现文件ObjectInputStream和ObjectOutputStream对象流的读写操作,构造函数需要传入一个流来实现JAVA对象的读写功能;可用于序列化,对象需要实现Serializable接口//java对象writeFileOutputStreamfileStream=newFileOutputStream("example.txt");ObjectOutputStreamout=newObjectOutputStream(fileStream);Exampleexample=newExample();out.writeObject(example);//读取java对象FileInputStreamfileStream=newFileInputStream("example.txt");ObjectInputStreamin=newObjectInputStream(fileStream);例子=(例子)in.readObject();PipedInputStream和PipedOutputStream管道流,适合在两个线程中传输数据,一个线程通过管道输出流发送数据,另一个线程通过管道输入流读取数据,实现两个线程之间的数据通信//创建发送者对象Sendersender=newSender();//创建接收者对象Receiverreceiver=newReceiver();//获取输出管道流//获取输入输出管道流/链接两条管道,这一步很重要,连接输入流和输出流outputStream.connect(inputStream);sender.start();//启动Sender线程receiver.start();//启动receiver线程多个InputStreams合并为一个InputStream,允许应用程序连续合并多个输入流InputStreamin1=newFileInputStream("example1.txt");InputStreamin2=newFileInputStream("example2.txt");SequenceInputStreamsequenceInputStream=newSequenceInputStream(in1,in2);//数据读取intdata=sequenceInputStream.read();FilterInputStream和FilterOutputStream使用装饰器模式添加流的附加功能,子类构造参数NeedanInputStream/OutputStreamByteArrayOutputStreamout=newByteArrayOutputStream(2014);//数据写入,使用DataOutputStream装饰一个InputStream//使用InputStream具有处理基础数据的能力DataOutputStreamdataOut=newDataOutputStream(out);dataOut.writeDouble(1.0);//数据读取dataIn.readDouble();DataInputStream和DataOutputStream(Filter流的子类)为其他流增加处理各种基本类型数据的能力,如byte、int、String)推回输入流,可以将读取到的一些数据返回到输入流的缓冲区中。PrintStream(FilterOutputStream的子类)打印流,功能类似于System.out.print2JAVA.IO字符流21.png从字节流和字符流的方向图来看,它们是一一对应的,比如CharArrayReader和ByteArrayInputStreamConversion字节流和字符流:InputStreamReader可以将InputStream转Reader,OutputStreamReader可以将OutputStream转Writer//InputStream转ReaderInputStreaminputStream=newByteArrayInputStream("program".getBytes());InputStreamReaderreader=newInputStreamReader(inputStream,StandardCharsets.UTF_8);//OutputStream到WriterOutputFileStreamout=newtream("example.txt");OutputStreamWriterwriter=newOutputStreamWriter(out);//以字符为单位读写writer.write(reader.read(newchar[2]));区别:字节流读取单位是字节,字符流读取单位是字符;一个字符是由字节组成的,比如可变字长编码UTF-8用1~4个字节表示3乱码和字符流字符用不同的编码表示,它的字节长度(字长)是不同的比如“程”的utf-8编码格式,由[-25][-88][-117]组成。ISO_8859_1编码是单字节[63]通常,资源的操作都是面向字节流的。但是,当数据资源按照不同的字节编码转换为字节时,其内容是不同的,容易造成乱码。问题两种乱码场景下encode和decode使用的字符编码不一致:资源使用UTF-8编码,代码中使用GBK解码打开使用字节流读取字节数不符合指定字符长度:字符由确定,例如“程”的utf-8格式为三个字节;如果在InputStream中每两个字节读一次流,然后转成String(java默认编码是utf-8),这时候就会出现乱码(半个汉字,猜猜是什么)ByteArrayInputStreamin=newByteArrayInputStream("程序不错".getBytes());byte[]buf=newbyte[2];//读取流中的两个字节in.read(buf);//读取数据System.out.println(newString(buf)));//乱码---result----?//乱码场景1,知道资源的字符编码,就可以使用对应的字符编码来解码解决乱码场景2.可以一次读取所有字节,然后一次编码。但是对于大文件流,这是不现实的,所以随着字符流的出现,使用InputStreamReader和OutputStreamReader将字节流转换为字符流,其中可以指定字符编码,然后以字符为单位进行处理,可以解决乱码人物。InputStreamReaderreader=newInputStreamReader(inputStream,StandardCharsets.UTF_8);4字符集和字符编码的概念区分字符集和字符编码的关系,字符集是规范,字符编码是规范的具体实现;字符集规定了符号与二进制码值的唯一对应关系,但没有规定具体的存储方式;unicode、ASCII、GB2312、GBK都是字符集;ASCII、GB2312、GBK都是字符集和字符编码;注意不要混淆两者的区别;而unicode的具体实现有UTF-8、UTF-16、UTF-32,最早的ASCII码是用一个字节(8bit)来指定字符和二进制的映射关系。标准的ASCII码规定了128个字符,这在英语世界中已经足够了。.但是如何映射中文、日文等其他文字符号呢?因此,unicode(统一字符集)出现在其他更大的字符集中。早期是用2个字节表示1个字符,整个字符集可以容纳65536个字符。但是还是不够用,所以扩展为4个字节来表示一个字符。目前支持的范围是U+010000~U+10FFFF。说unicode是两个字节是错误的;~4个字节用于存储;UTF-16一般为两个字节(U+0000~U+FFFF范围),如果两个字节存不下,就用4个字节;UTF-32是固定的四字节unicode表示的字符会以“U+”开头,后面跟十六进制数,比如“字符”的编码是U+5B57UTF-8编码和unicode字符集范围Unicode(Binary)UTF-8编码(Binary)UTF-8编码byte长度U+0000~U+007F0000000000000000000000000XXXXXXX0XXXXXX1U+0080~U+07FF000000000000000000000YYYYYXXXXXX110YYYYY10XXXXXX2U+0800~U+FFFF0000000000000000ZZZZYYYYYYXXXXXX1110ZZZZZ10YYYYYY10XXXXXX3U+010000~U+10FFFF00000000000AAAZZZZZZYYYYYYXXXXXX11110AAA10ZZZZZZZ10YYYYYY10XXXXXX4程序分为内码和外码,long其实是指java-8s的默认编码代码是基于内存对齐的原则,容易处理。外部代码倾向于使用变长代码。变长码将常用字符编码为短码,将稀有字符编码为长码,节省存储空间和传输带宽。JDK8的字符串使用char[]来存储字符,char是两个字节大小,使用UTF-16编码(内码)。unicode规定的汉字在U+0000~U+FFFF,所以使用char(UTF-16编码)存储汉字不会出现乱码。JDK9以后,字符串存储在byte[]数组中,因为有一些字符不能存储在一个char中,比如emoji字符,JDK9用bytes存储字符串更容易扩展。如果字符串的内容都是ISO-8859-1/Latin-1字符(1??字符1字节),则使用ISO-8859-1/Latin-1编码存储字符串,否则使用UTF-16编码存储数组(2or4bytes)System.out.println(Charset.defaultCharset());//输出java默认编码for(byteitem:"program".getBytes(StandardCharsets.UTF_16)){System.out.print("["+item+"]");}System.out.println("");for(byteitem:"program".getBytes(StandardCharsets.UTF_8)){System.out.print("["+item+"]");}----result----UTF-8//java默认编码UTF-8[-2][-1][122][11][94][-113]//UTF_16:6字节?[-25][-88][-117][-27][-70][-113]//UTF_8:6字节普通“程序”的UTF-16编码实际输出6字节,多出两个字节,什么情况?尝试另一个字符输入for(byteitem:"Cheng".getBytes(StandardCharsets.UTF_16)){System.out.print("["+item+"]");}---result--[-2][-1][122][11]可以看出UTF-16编码的字节多了两个字节[-2][-1],十六进制值为0xFEFF。用于识别编码顺序是大端还是小端。以字符'中'为例,它的unicode十六进制为4E2D,当前面存放4E,后面存放2D时,就是Bigendian;前面是2D,后面是4E,就是Littleendian。FEFF表示使用Bigendian进行存储,FFFE表示使用Littleendian。为什么UTF-8没有字节顺序问题?个人看法,因为UTF-8是变长的,第一个字节的头部由0、110、0组成。1110和11110确定是否需要几个后续字节来组成一个字符。使用Bigendian易于阅读和处理,反之则不易处理。因此,强制使用Bigendian。其实感觉UTF-16可以强制使用Bigendian;但存在历史问题。..【编者推荐】Python虽好,但请不要盲目每个项目都用它!红帽开放混合云助力企业成为数字原生代企业分析鸿蒙系统的helloworld程序如何调用,SYS_RUN有什么作用,5G为何突然“不流行”?新方向、新特性:Python3.9完整版发布
