本篇涉及到的流:
1.PrintWriter:字符
打印输出流
2.PrintStream:字节
打印输出流
3.SequenceInputStream :合并多个字节输入流
4.RandomAccessFile:随机操做文件
5.ObjectOutputStream与ObjectInputStream :对象的序列化流
6.DataInputStream与DataOutputStream :基本数据类型操做流
7.ByteArrayInputStream与ByteArrayOutputStream:字节数组操做流java
字符
打印输出流File file 文件 File file, String csn 文件,字符集 String fileName 文件名 String fileName, String csn 文件名,字符集 OutputStream out 字节输出流 OutputStream out, boolean autoFlush 字节输出流,是否自动刷新缓冲区 Writer out 字符输出流 Writer out, boolean autoFlush 字符输出流,是否自动刷新缓冲区
不管是文件也好,字符串也好,字节输出流,字符输出流也好,总之一句话:
给我一个输出流
,还你一个PrintWriter
git
public class PrintStreamTest { public static void main(String[] args) throws IOException { BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in)); //使用控制台输出流建立一个自动刷新缓冲区的PrintWriter对象 PrintWriter pw = new PrintWriter(System.out,true); String line = null; while ((line = bfr.readLine()) != null) { //pw.write(line.toUpperCase());//不带换行 //pw.flush(); pw.println(line.toUpperCase());//自带换行,自带刷新 } bfr.close(); pw.close(); } }
想要将键盘录入保存到文件中,只要将
控制台输出流
换成文件输出流
便可
其余部分同上github
String path = "I:\\Java\\Base\\Thinking\\src\\IOTest\\PrintWriter.txt"; PrintWriter pw = new PrintWriter(new FileWriter(path), true);
字节
打印输出流File file 文件 File file, String csn 文件,字符集 String fileName 文件名 String fileName, String csn 文件名,字符集 OutputStream out 字节输出流 OutputStream out, boolean autoFlush 字节输出流,是否自动刷新缓冲区 OutputStream out, boolean autoFlush, String encoding 字节输出流,是否自动刷新缓冲区,字符集
不管是文件也好,字符串也好,字节输出流,总之一句话:
给我一个字节输出流
,还你一个PrintStream
编程
public class PrintWriterTest { public static void main(String[] args) { try { int a = Integer.parseInt("a"); } catch (NumberFormatException e) { e.printStackTrace(); } } }
java.lang.NumberFormatException: For input string: "a" at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.base/java.lang.Integer.parseInt(Integer.java:652) at java.base/java.lang.Integer.parseInt(Integer.java:770) at top.toly.IO.io.其余流.PrintWriterTest.main(PrintWriterTest.java:12)
全部异常继承自:Throwable 类
其中有个不起眼的方法printStackTrace(),通常放着也没人管
但它有的重载的方法void printStackTrace(PrintStream s)
能够自定义输出流数组
public class PrintStreamTest { public static void main(String[] args) throws FileNotFoundException { try { int a = Integer.parseInt("a"); } catch (NumberFormatException e) { e.printStackTrace();//默认是输出到控制台:即System.out流 //将信息打印到F:\log.txt文件中 e.printStackTrace(new PrintStream("F:\\log.txt")); } } }
也能够加入异常的时间微信
//将信息打印到F:\log.txt文件中 PrintStream ps = new PrintStream("F:\\log.txt"); ps.println(new SimpleDateFormat(" G yyyy/MM/dd 星期--EE a hh:mm:ss ").format(new Date().getTime())); e.printStackTrace(ps);//默认是输出到控制台:即System.out流
InputStream s1, InputStream s2 两个字节流对象,先读s1,再s2 (Enumeration<? extends InputStream> e)
public class SISTest { public static void main(String[] args) throws Exception { FileInputStream fis1 = new FileInputStream("I:\\Java\\Base\\Thinking\\src\\IOTest\\FileInputStream.txt"); FileInputStream fis2 = new FileInputStream("I:\\Java\\Base\\Thinking\\src\\IOTest\\TxtInfo.ini"); //使用Vector获取Enumeration对象 Vector<InputStream> vec = new Vector<>(); vec.add(fis1); vec.add(fis2); SequenceInputStream sis = new SequenceInputStream(vec.elements());//合并输入流 //建立输出流 FileOutputStream fos = new FileOutputStream("I:\\Java\\Base\\Thinking\\src\\IOTest\\SequenceInputStream.txt"); int len = 0; byte[] buf = new byte[1024]; while ((len = sis.read(buf)) != -1) { fos.write(buf, 0, len); } sis.close(); fos.close(); } }
当一个文件过大时,能够分割成多个小块
好比将一个1GB的电影分割成10份,每份100+M,因为字节不完整,致使没法播放
因此别人也不知道是什么电影 想看时用合并流合并一下,就能正常播放了。
能够搞个切合播放器,关闭播放器将电影切割,须要打开时碎片合并,而后就神不知鬼不觉。dom
目标文件Activity.md --7.34 KB (7,521 字节),按3KB大小切ide
public class SplitFile { public static void main(String[] args) throws Exception { String pathS = "I:\\Java\\Base\\Thinking\\src\\IOTest\\Activity.md"; File fileS = new File(pathS); FileInputStream fis = new FileInputStream(pathS); //获取待切分文件名,以它做文文件夹,放入切分后的 File parent = new File(fileS.getParentFile().getAbsolutePath() + File.separator + fileS.getName().split("\\.")[0]); parent.mkdir(); int count = 0; int len = 0; byte[] buf = new byte[1024 * 3];//每份3kb,最后一份小于或等于3kb while ((len = fis.read(buf)) != -1) { File fileT = new File(parent, (count++) + ".temp"); FileOutputStream fos = new FileOutputStream(fileT); fos.write(buf, 0, len); fos.close(); } fis.close(); } }
合并网站
public class SISTest { public static void main(String[] args) throws Exception { FileInputStream fis1 = new FileInputStream("I:\\Java\\Base\\Thinking\\src\\IOTest\\Activity\\0.temp"); FileInputStream fis2 = new FileInputStream("I:\\Java\\Base\\Thinking\\src\\IOTest\\Activity\\1.temp"); FileInputStream fis3 = new FileInputStream("I:\\Java\\Base\\Thinking\\src\\IOTest\\Activity\\2.temp"); //使用Vector获取Enumeration对象 ArrayList<InputStream> list = new ArrayList<>(); list.add(fis1); list.add(fis2); list.add(fis3); //基于ArrayList合并流:需自定义Enumeration final Iterator<InputStream> it = list.iterator(); Enumeration<InputStream> en = new Enumeration<>() { @Override public boolean hasMoreElements() { return it.hasNext(); } @Override public InputStream nextElement() { return it.next(); } }; SequenceInputStream sis = new SequenceInputStream(en);//合并输入流 //建立输出流 FileOutputStream fos = new FileOutputStream("I:\\Java\\Base\\Thinking\\src\\IOTest\\Activity\\Activity.md"); int len = 0; byte[] buf = new byte[1024]; while ((len = sis.read(buf)) != -1) { fos.write(buf, 0, len); } sis.close(); fos.close(); } }
使用ObjectOutputStream将对象序列化成为数据输出-->将对象持久存储
使用ObjectInputStream进行读取序列化的数据-->恢复先前对象
只能序列化堆中的对象,static修饰的成员变量不能被序列化
transient修饰的成员变量,即便在堆内存中也不会被序列化this
private static void writeObject() throws IOException { String path = "I:\\Java\\Base\\Thinking\\src\\IOTest\\ObjectOutputStream.txt"; ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path)); //Person须要序列化implements Serializable:不然ERROR----NotSerializableException Person toly = new Person("捷特", 24); oos.writeObject(toly); oos.close(); }
public class Person implements Serializable { String name; int age; public Person(String name, int age) { this.name = name; this.age = age; } //get()、set()、toSring()省略 }
至关于给个文件给你,你直接读出来一个对象,建立,赋值什么的都已经搞定了
对于十分复杂的对象序列化仍是很方便的,但因为是IO,相对比较耗时
private static void readObject() throws IOException, ClassNotFoundException { String path = "I:\\Java\\Base\\Thinking\\src\\IOTest\\ObjectOutputStream.txt"; ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path)); Person toly = (Person) ois.readObject(); System.out.println(toly);//Person{name='捷特', age=24}
1.该类不是算是IO体系中子类。而是直接继承自Object。
2.可是它是IO包中成员。由于它具有读和写功能,内部封装字节输入流和输出流。
3.内部封装数组,经过指针对数组的元素进行操做,getFilePointer获取指针位置,经过seek改变指针的位置
4.只能操做磁盘文件,
File file, String mode rw :读写模式 r : 只读 String name, String mode
public class RAF_Test { public static void main(String[] args) throws IOException { String path = "I:\\\\Java\\\\Base\\\\Thinking\\\\src\\\\IOTest\\RandomAccessFile.txt"; RandomAccessFile raf = new RandomAccessFile(path, "rw"); raf.write("张风捷特烈".getBytes()); raf.write(38); raf.write(527654); raf.close(); } }
可见38和527654两个int值以
&
字符展示出来,utf-8码表第38为是&
这情有可原,527654怎么也来插一脚
众所周知,一个int占4个字节,一个字节是8位,也就是一个int占32位,转换成二进制即下面:
3366 0000 0000 0000 1000 0000 1101 0010 0110 38 0000 0000 0000 0000 0000 0000 0010 0110 RandomAccessFile写入时int只写入低8位(由于字符写入,一次只能写一个字节即8位),即0010 0110
解决方法:将一个int分为4次来读,每次读一个字节(8位),写入文件
raf.writeInt(527654);//RandomAccessFile内部已经封装
RandomAccessFile rafR = new RandomAccessFile(path, "r"); byte[] buf = new byte[9];//一个utf-8汉字占三个字节,这里一次读三个汉字 rafR.read(buf); System.out.println(new String(buf));//张风捷 //这里用8,由于两个汉字3*2=6字节,加上2个&&一共8个字节。 byte[] buf2 = new byte[8]; rafR.read(buf2); System.out.println(new String(buf2));//特烈&& //读取int值:若是上面不是8,而是9,那么527654的字节就不完整,会报错 System.out.println(rafR.readInt());//527654
RandomAccessFile rafR = new RandomAccessFile(path, "r"); rafR.seek(3);//将读取的指针移到第4个字节 byte[] buf = new byte[3]; rafR.read(buf); System.out.println(new String(buf));//风
String path = "I:\\\\Java\\\\Base\\\\Thinking\\\\src\\\\IOTest\\RandomAccessFile.txt"; RandomAccessFile rafRW = new RandomAccessFile(path, "rw"); rafRW.write("张风捷特".getBytes()); rafRW.write(38); rafRW.write(527654); rafRW.writeInt(527654); rafRW.seek(40); rafRW.write("巫缨".getBytes()); rafRW.close();
private static void write() throws IOException { DataOutputStream dos = new DataOutputStream(new FileOutputStream(path)); dos.writeBoolean(true);//1字节 dos.writeInt(3366);//4字节 dos.writeFloat(3.14f);//4字节 dos.close(); }
DataInputStream dis = new DataInputStream(new FileInputStream(path)); //注意按添加的顺序读取 System.out.println(dis.readBoolean());//true System.out.println(dis.readInt());//3366 System.out.println(dis.readFloat());//3.14
ByteArrayInputStream :在构造的时候,须要数据源:一个字节数组,缓冲区会随数据自动增加。
ByteArrayOutputStream: 在构造的时候,该对象中已经内部封装了可变长度的字节数组,是数据目的地。
public class BAIS_BAOS_Test { public static void main(String[] args) throws IOException { ByteArrayInputStream bais = new ByteArrayInputStream("张风捷特烈".getBytes()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.out.println(baos.size());//0 int by = 0; while ((by = bais.read()) != -1) { baos.write(by); } System.out.println(baos.size());//15 = 3 * 5 //写到控制台 baos.writeTo(System.out);//张风捷特烈 //写到文件 String path = "I:\\Java\\Base\\Thinking\\src\\IOTest\\ByteArrayOutputStream.txt"; baos.writeTo(new FileOutputStream(path)); } }
其余几个操做相似,顺便提一下
类 | IO | 流类型 | 操做数据 |
---|---|---|---|
ByteArrayInputStream | 输入流I | 字节流 | 字节数组 |
ByteArrayOutputStream | 输出流O | 字节流 | 字节数组 |
CharArrayReader | 输出流I | 字符流 | 字符数组 |
CharArrayWriter | 输出流O | 字符流 | 字符数组 |
StringReader | 输出流I | 字符流 | 字符串 |
StringWriter | 输出流O | 字符流 | 字符串 |
项目源码 | 日期 | 备注 |
---|---|---|
V0.1--无 | 2018-10-12 | Java总结IO篇之其余IO流对象 |
V0.2--无 | - | - |
笔名 | 微信 | 爱好 | |
---|---|---|---|
张风捷特烈 | 1981462002 | zdl1994328 | 语言 |
个人github | 个人简书 | 个人CSDN | 我的网站 |
1----本文由张风捷特烈原创,转载请注明 2----欢迎广大编程爱好者共同交流 3----我的能力有限,若有不正之处欢迎你们批评指证,一定虚心改正 4----看到这里,我在此感谢你的喜欢与支持