内存操作流
这个流不关联任何文件,只能在内存中数据,自己在内存中维护着一个缓冲区,我们可以往他维护的缓冲区不断的写入数据,也可以从缓冲区中取出我们写入的数据
ByteArrayOutputStream
ByteArrayInputStream:此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray () 和 toString () 获取数据。内存操作流无需关闭
案例演示:
public class MyTest2 { public static void main(String[] args) throws IOException { //ByteArrayOutputStream() //创建一个新的 byte 数组输出流。 //创建出内存操作流 他维护着一个字节数组来充当缓冲区 ByteArrayOutputStream bos = new ByteArrayOutputStream(); bos.write("好好学习".getBytes()); bos.write("天天向上".getBytes()); bos.write("爱生活".getBytes()); bos.write("爱Java".getBytes()); byte[] bytes = bos.toByteArray(); read(bytes); } private static void read(byte[] bytes) throws IOException { /* ByteArrayInputStream( byte[] buf) 创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。*/ ByteArrayInputStream bis = new ByteArrayInputStream(bytes); byte[] bytes1 = new byte[1024]; int len = bis.read(bytes1); String s = new String(bytes1, 0, len); System.out.println(s); } }
操作字符数组
CharArrayWrite:此类实现一个可用作字符输入流的字符缓冲区。
CharArrayReader:此类实现一个可用作 Writer 的字符缓冲区。缓冲区会随向流中写入数据而自动增长。可使用 toCharArray() 和 toString() 获取数据。
案例演示:
public class MyTest3 { public static void main(String[] args) throws IOException { CharArrayWriter charArrayWriter = new CharArrayWriter(); charArrayWriter.write("abc"); charArrayWriter.write("abc"); String s = charArrayWriter.toString();//调用toString()来获取字符数组 System.out.println(s); char[] chars = charArrayWriter.toCharArray();//调用toCharArray()来获取字符数组 System.out.println(chars); } }
操作字符串
StringReader:其源为一个字符串的字符流
StringWriter:一个字符流,可以用其回收在字符串缓冲区中的输出来构造字符串。关闭 StringWriter 无效。此类中的方法在关闭该流后仍可被调用,而不会产生任何IO异常
public class MyTest4 { public static void main(String[] args) { StringWriter stringWriter = new StringWriter(); stringWriter.write("abc"); stringWriter.write("abc"); stringWriter.write("abc"); stringWriter.write("abc"); stringWriter.write("abc"); String s = stringWriter.toString(); } }
ByteArrayOutputStream/ ByteArrayInputStream
ByteArrayInputStream: 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read
方法要提供的下一个字节。关闭 ByteArrayInputStream无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何IO异常。
ByteArrayOutputStream:此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和toString() 获取数据。关闭ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何IOException。
案例演示:将多个mp3文件,拼接成一个mp3文件
public class MyTest { public static void main(String[] args) throws IOException { FileInputStream in1 = new FileInputStream("许巍 - 曾经的你.mp3"); FileInputStream in2 = new FileInputStream("许巍 - 蓝莲花.mp3"); FileOutputStream out = new FileOutputStream("C:\\Users\\jjh\\Desktop\\歌曲大连唱.mp3"); ArrayList<FileInputStream> list = new ArrayList<>();//创建集合 list.add(in1); list.add(in2);//把两手哥存入集合 ByteArrayOutputStream bos = new ByteArrayOutputStream(); int len=0; byte[] bytes = new byte[1024 * 8]; //读取两首歌的字节数据,一块先缓存到内存操作流所维护的字节数组中 for (FileInputStream in : list) { while ((len = in.read(bytes)) != -1) { bos.write(bytes, 0, len); } in.close(); } //取出两首歌的字节数据 byte[] allBytes = bos.toByteArray(); //读取两首歌的字节数据,往硬盘上写 ByteArrayInputStream bis = new ByteArrayInputStream(allBytes); int len2 = 0; byte[] bytes2 = new byte[1024 * 8]; while ((len2=bis.read(bytes2))!=-1){ out.write(bytes2,0,len2); out.flush(); } out.close(); System.out.println("合并完成"); } }
打印流
他只关联目的地,不关联源文件。它只能输出,不能读取。
字节打印流
PrintStream(File file) : 创建具有指定文件且不带自动行刷新的新打印流
PrintStream(String fileName) :创建具有指定文件名称且不带自动行刷新的新打印流
案例演示:
public class MyTest { public static void main(String[] args) throws IOException { PrintStream printStream = new PrintStream(new File("b.txt")); //通过创建得来的字节打印流,关联的是文件,那么你是往文件中打印数据 printStream.write("曾梦想仗剑走天涯,看一看世界的繁华".getBytes()); printStream.write("\r\n".getBytes()); printStream.println("曾梦想仗剑走天涯,看一看世界的繁华"); printStream.close(); //System.out 获取出的这个字节打印流,关联的设备是屏幕 PrintStream out = System.out; //关联屏幕 out标准”输出流。此流已打开并准备接受输出数据。通常,此流对应于显示器 out.write("abc".getBytes()); out.print(20000); out.println(300000); System.out.println(); out.close(); } }
字符打印流
PrintWriter 字符打印流
PrintWriter(OutputStream out, boolean autoFlush):通过现有的 OutputStream 创建新的 PrintWriter。如果启用了自动刷新,则只有在调用 println、printf 或 format 的其中一个方法时才可能完成此操作。参数2是是否要开启自动刷新
案例演示1:
public class MyTest2 { public static void main(String[] args) throws FileNotFoundException { PrintWriter printWriter = new PrintWriter("c.txt"); printWriter.write("abc"); printWriter.print(100); printWriter.flush(); printWriter.close(); } }
案例演示2:
public class MyTest3 { public static void main(String[] args) throws FileNotFoundException { // PrintWriter(OutputStream out, boolean autoFlush) // 通过现有的 OutputStream 创建新的 PrintWriter。 PrintWriter printWriter = new PrintWriter(new FileOutputStream("d.txt"), true); //printWriter.write("abc");//因为没有调上面说的三种方法,不手动刷新的话就不显示 printWriter.println("abc"); printWriter.flush(); printWriter.close(); } }
案例演示3:打印流复制文本文件
public class MyTest4 { public static void main(String[] args) throws IOException { BufferedReader bfr = new BufferedReader(new FileReader("MyTest.java")); PrintWriter printWriter = new PrintWriter(newFileOutputStream("MyTest222.java"),true); String line=null; while ((line=bfr.readLine())!=null){ printWriter.println(line);//调用了println所以我们不需要手动刷新 } bfr.close(); printWriter.close(); } }
随机访问流
此类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过 getFilePointer 方法读取,并通过 seek方法设置。
RandomAccessFile(File file, String mode):创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定
mode 参数指定用以打开文件的访问模式。允许的值及其含意为:
"r":以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
"rw":打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。
"rws":打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
"rwd": 打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。
案例1:把一首歌用随机访问流复制三份
public class MyTest3 { public static void main(String[] args) throws IOException { RandomAccessFile in = new RandomAccessFile("许巍 - 曾经的你.mp3", "rw"); RandomAccessFile out = null; byte[] bytes = new byte[1024]; int len = 0; for (int i = 0; i < 3; i++) { out = new RandomAccessFile((i + 10) + "许巍 - 曾经的你.mp3", "rw"); while ((len = in.read(bytes)) != -1) { out.write(bytes, 0, len); } in.seek(0);//把文件指针置于文件的开头 out.close(); } in.close(); } }
案例2:歌曲的断点复制
public class MyTest4 { public static void main(String[] args) throws IOException { RandomAccessFile in = new RandomAccessFile("许巍 - 蓝莲花.mp3", "rw"); File mbFile = new File("C:\\Users\jjh\\Desktop\\许巍 - 蓝莲花22222.mp3"); RandomAccessFile out = new RandomAccessFile(mbFile, "rw"); //第二次来复制了 String s = new BufferedReader(new FileReader("ls.txt")).readLine(); //读取临时文件 long len2 = Long.parseLong(s);//获取临时文件的长度(向下转型) if(mbFile.exists()&&mbFile.length()==len2){ //如果临时文件存在而且目标文件的长度和临时文件相等的话继续执行 in.seek(len2);//把指针位置置于len2这样就可以断点下载 out.seek(len2); }else{ in.seek(0);//设置文件指针的位置 out.seek(0); } int len=0; byte[] bytes = new byte[1024]; int i=1; try { while ((len = in.read(bytes)) != -1) { //i++; out.write(bytes, 0, len); /* if(i>=2500){ System.out.println(1/0); }*/ //这是自己制造的异常情况让复制终止 } }catch (Exception e){ long filePointer = in.getFilePointer(); //获取文件指针的位置 System.out.println(filePointer); PrintWriter printWriter = new PrintWriter(new File("ls.txt")); //创建一个临时文件来记录文件复制的字节数 printWriter.println(filePointer); printWriter.flush(); printWriter.close(); } in.close(); out.close(); } }
其他输入流的串联(顺序流)
SequenceInputStream: 表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止
SequenceInputStream(InputStream s1, InputStream s2):通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从SequenceInputStream 读取的字节
案例演示:用顺序流把三首歌拼成一首歌
public class MyTest { public static void main(String[] args) throws IOException { FileInputStream in1 = new FileInputStream("许巍 - 曾经的你.mp3"); FileInputStream in2 = new FileInputStream("许巍 - 蓝莲花.mp3"); FileInputStream in3 = new FileInputStream("许巍 - 蓝莲花.mp3"); FileOutputStream out = new FileOutputStream("gequ.mp3");//输出 SequenceInputStream sequenceInputStream = new SequenceInputStream(in1, in2); SequenceInputStream sequenceInputStream1 = new SequenceInputStream(sequenceInputStream, in3); int len=0; byte[] bytes = new byte[1024 * 8]; while ((len=sequenceInputStream1.read(bytes))!=-1){ out.write(bytes,0,len); out.flush(); } out.close(); sequenceInputStream1.close(); } }
Properties
Properties 继承Hashtable 是一个双列集合,规定键值都是字符串类型
案例演示1:
public class MyTest { public static void main(String[] args) { Properties properties = new Properties(); properties.setProperty("username", "张三"); properties.setProperty("password", "123456"); String username = properties.getProperty("username"); //当这个键对应的值得没找到,可以返回这个备用值,参数2 可以指定一个备用的值 String pwd = properties.getProperty("password","654321"); System.out.println(username); System.out.println(pwd); } }
案例演示2:把属性集合中的键值对数据写入配置文件中保存 (store())
public class MyTest2 { public static void main(String[] args) throws IOException { Properties properties = new Properties(); properties.setProperty("username", "张三"); properties.setProperty("password", "123456"); //参数2:是注释 一般给个null 写个默认注释 properties.store(new FileOutputStream("user.properties"),"hehehe");
案例演示3:把配置文件中的键值对数据,再次都会属性集合中
public class MyTest3 { public static void main(String[] args) throws IOException { //Properties 读取配置文件,对文件有要求,1.键值对,是 = 拼接 2.属性集合读取到的这个文件的后缀名是以.properties Properties properties = new Properties(); //读取配置文件 properties.load(new FileInputStream("user.properties")); System.out.println(properties); } }
案例演示4:
public class MyTest04 { /*我有一个文本文件file.txt,我知道数据是键值对形式的,但是不知道内容是什么。 请写一个程序判断是否有"lisi"这样的键存在,如果有就改变其实为"100" file.txt文件内容如下: zhangsan = 90 lisi = 80 wangwu = 85*/ public static void main(String[] args) throws IOException { Properties properties = new Properties(); properties.load(new FileInputStream("file.txt")); //先读写这个文件 Set<String> names = properties.stringPropertyNames(); //stringPropertyNames() //返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。其键或值不是 String 类型的属性被忽略 if (names.contains("lisi")){ properties.setProperty("lisi","100"); properties.store(new FileOutputStream("d.txt"),null); //最后写入保存 System.out.println(properties); }