InputStream与OutputStream 的基本方法说明
1. InputStream 从流中读取数据:
InputStream 是所有的输入字节流的父类,它是一个抽象类。
ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。
PipedInputStream 是从与其它线程共用的管道中读取数据,与Piped 相关的知识后续单独介绍。
ObjectInputStream 和所有FilterInputStream的子类都是装饰流(装饰器模式的主角)。
意思是FileInputStream类可以通过一个String路径名创建一个对象,FileInputStream(String name)。
而DataInputStream必须装饰一个类才能返回一个对象,DataInputStream(InputStream in)。
1. int read( ); //读取一个字节,返回值为所读的字节 对应的AsII编码
2. int read( byte b[ ] ); //读取多个字节,放置到字节数组b中,通常读取的字节数量为b的长度,返回值为实际读取的字节的数量
3. int read( byte b[ ], int off, int len ); //读取len个字节,放置到以下标off开始字节数组b中,返回值为实际读取的字节的数量
4. int available( ); //返回值为流中尚未读取的字节的数量
5. long skip( long n ); //读指针跳过n个字节不读,返回值为实际跳过的字节数量
6. close( ); //流操作完毕后必须关闭
◇ 使用输入流中的标记:
void mark( int readlimit ); //记录当前读指针所在位置,readlimit 表示读指针读出readlimit个字节后所标记的指针位置才失效
void reset( ); //把读指针重新指向用mark方法所记录的位置
boolean markSupported( ); //当前的流是否支持读指针的记录功能
2.OutputStream 输出数据:
OutputStream 是所有的输出字节流的父类,它是一个抽象类。
ByteArrayOutputStream、FileOutputStream是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据,
ObjectOutputStream 和所有FilterOutputStream的子类都是装饰流。具体例子跟InputStream是对应的。
1. void write( int b ); //往流中写一个字节b
2. void write( byte b[ ] ); //往流中写一个字节数组b
3. void write( byte b[ ], int off, int len ); //把字节数组b中从下标off开始,长度为len的字节写入流中
4. ◇ flush( ) //刷空输出流,并输出所有被缓存的字节,由于某些流支持缓存功能,该方法将把缓存中所有内容强制输出到流中。
5. close( ); //流操作完毕后必须关闭
1.内存流
public static void main(String[] args) throws IOException { /*字节数组 * ByteArrayInputStream * ByteArrayOutputStream * 字符数组 * CharArrayReader * CharArrayWriter * */ //字节数组输入流对象 /* byte [] b = {97,98,99,100,101,97,98,99,100,101}; //源数组对象(源文件对象) ByteArrayInputStream bais = new ByteArrayInputStream(b); //只读一次 // int a = bais.read(); // System.out.println(a); //97 //一次读完 // byte [] piao = new byte[bais.available()]; // System.out.println(bais.available()); //10 // bais.read(piao); // System.out.println(Arrays.toString(piao)); //循环读 byte [] piao = new byte[4]; int len = -1; while((len = bais.read(piao))!=-1){ System.out.print(new String(Arrays.copyOf(piao, len))); for(byte c:Arrays.copyOf(piao, len)){ System.out.print(c+" "); } } */ //字节数组输出流对象 /* byte [] b = new byte[1000]; //将程序的字节数组中 的数组 写入 字节流里 ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] data = {97,98,99,100,101,97,98,99,100,101}; bos.write(data,0,data.length); System.out.println(bos.toString()); //abcdeabcde System.out.println(Arrays.toString(bos.toByteArray()));//[97, 98, 99, 100, 101, 97, 98, 99, 100, 101] FileOutputStream fos = new FileOutputStream("aa.txt"); bos.writeTo(fos); //将字节数组输出流中的数据 写入文件输出流中 //// abcdeabcde fos.write(50); // abcdeabcde2 ,把2也写进去 */ //字符数组输入流对象 /* char [] ch = {'A','Z','C','D','a'}; CharArrayReader car= new CharArrayReader(ch); //只读一次 // int a = car.read(); // System.out.println(a);//65 //一次读完 // char[] piao = new char[ch.length]; // car.read(piao); // for(char c:piao){ // System.out.print(c+" "); //A Z C D a // } //循环读 char [] piao = new char[3]; int len = -1; while((len = car.read(piao))!=-1){ System.out.print(new String(Arrays.copyOf(piao, len))); for(char c:Arrays.copyOf(piao, len)){ System.out.print(c+" "); //AZCA Z C DaD a } } */ //字符数组输出流对象 CharArrayWriter caw = new CharArrayWriter(); char [] ch = "我们好".toCharArray(); caw.write("你好,我好,啦啦啦"); caw.append("么么哒"); //CharSequence 接口 caw.flush(); //System.out.println(caw.toString());//你好,我好,啦啦啦么么哒 // for(char b:caw.toCharArray()){ // System.out.print(b); // } FileWriter fw = new FileWriter("tt.txt"); caw.writeTo(fw); fw.write(""); fw.flush(); //你好,我好,啦啦啦么么哒 } }
2.文件流
FileInputStream 从本地文件中读取数据 从硬盘存在的一个文件中,读取其内容到程序中。使用FileInputStream ,要读取的文件一定要存在。否则抛FileNotFoundException FileOutputStream 向本地文件中写入数据 创建一个File对象,表明要写入的文件位置。输出的物理文件可以不存在,当执行过程中,若不存在,会自动的创建。若存在,会将原有的文件覆盖
public static void main(String[] args) throws IOException { /* 文件流 文件字节流: FileInputStream ,FileOutputStream 文件字符流: FileReader, FileWriter */ //FileInputStream 文件字节输入流 //从本地文件中读取数据 //FileOutputStream 文件字节输出流 //向本地文件中写入数据
FileInputStream fis = new FileInputStream("aa.txt"); File f2 = new File("bb.txt"); FileOutputStream fos =new FileOutputStream(f2); /* //方法一: byte[] b = new byte[(int)f1.length()]; fis.read(b); fos.write(b); */ //方法二 byte[] b = new byte[89]; while(fis.available()>0){ int len = fis.read(b); //先读数据到数组中 fos.write(Arrays.copyOf(b, len)); //将b数组的数据写到目标文件中 } // FileReader 文件字符输入流 //目标文件 FileReader fr = new FileReader("hello.txt"); //aa123456789zxcvbnm /* //只读一次: int ch1 = fr.read(); System.out.println(ch1); //97 //一次读完 char[] ch2 = new char[50]; int len = fr.read(ch2); System.out.println(len); //23 */ //循环读 char[] ch3 = new char[10]; int len1 = -1; while((len1=fr.read(ch3))!=-1){ System.out.println(new String(Arrays.copyOf(ch3, len1))); } // 输出结果: // aa12345678 // 9zxcvbnm //FileWriter 文件字符输出流 File f = new File("world.txt"); //创建文件字符输出流对象 FileWriter fw = new FileWriter(f,true);// true 表示写入数据时是否可以拼接。false 表示覆盖 fw.write("你好呀呀呀呀"); char[] cbuf = "323你好丫丫33".toCharArray(); fw.write(cbuf); //你好呀呀呀呀323你好丫丫33 fw.flush();//手动刷新 }
3.缓冲流
- 什么时候会用到缓冲流
例如 :文件流程序 直接 操作磁盘文件 和 内存操作节点设备,如果频繁操作 效率低下。
缓冲流,可以把读写的数据线存储在缓冲区中,然后在适当的时候刷新(提交)到节点设备中,减少了操作次数
public static void main(String[] args) throws IOException { /* 缓冲流: 包装其他的流,达到高校的读写 BufferedInputStream 带有缓冲区的字节输入流 BufferedOutputStream 带有缓冲区的字节输出流 BufferedReader 带有缓冲区的字符输入流 BufferedWriter 带有缓冲区的字符输出流 */ /* //BufferedInputStream 带有缓冲区的字节输入流 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("aa.txt")); //abcdeabcde2 byte [] b = new byte[5]; int len = -1; while((len=bis.read(b))!=-1){ System.out.println(new String(Arrays.copyOf(b, len))); } // 输出结果: abcde // abcde // 2 */ /* //BufferedOutputStream 带有缓冲区的字节输出流 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("yy.txt")); bos.write("你好呀".getBytes()); //你好呀 bos.flush(); */ //BufferedReader 带有缓冲区的字符输入流 /* BufferedReader br = new BufferedReader(new FileReader("aa.txt")); char[] ch = new char[4]; //System.out.println(br.readLine()); //abcdeabcde2 一次读一行数据,如果读不到返回为空 String s = null; while((s = br.readLine()) != null){//一行一行的读 System.out.println(s); } */ //BufferedWriter 带有缓冲区的字符输出流 BufferedWriter bw = new BufferedWriter(new FileWriter("zz.txt")); bw.write("今天天气好好 "); // 表示换行 bw.append("好吗"); bw.newLine(); //表示换行 bw.append('好'); bw.flush(); // 输出结果:今天天气好好 // 好吗 // 好 } }
4.对象流
public class Student implements Serializable {
private String name;
private int id;
private int age;
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getId() {return id;}
public void setId(int id) {this.id = id;}
public int getAge() {return age;}
public void setAge(int age) { this.age = age;}
public Student(String name, int id, int age) {
super();
this.name = name;
this.id = id;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", id=" + id + ", age=" + age + "]";
}
}
public static void main(String[] args) throws Exception { Student student = new Student("aa",1434,12); File file = new File("student.txt"); FileOutputStream fos = new FileOutputStream(file); //创建对象输出流 步骤:把 数据输出流对象 作为 对象输出流对象的 参数 ObjectOutputStream oos = new ObjectOutputStream(fos); oos.flush();//手动刷新 oos.writeObject(student);//将对象数据写入到Student.txt文件中 //writeObject :进行对象序列化操作 /*需要注意的细节: * 1.如果对象需要被写出到文件上,那么对象所属的类必须要实现Serializable接口。 Serializable接口没有任何的方法,是一个标识接口。 * 2.对象以对象流形式保存时需要进行序列化操作 */ //后开先关原则 oos.close(); fos.close(); //创建对象输入流 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("student.txt"))); Object o = ois.readObject();//读操作 //readObject() 反序列化操作: System.out.println(o); // Student [name=aa, id=1434, age=12] } }
5.打印流
- 标准输入输出流以及标准错误输出流
System.out 是一个特殊的 PrintStream “标准”输出流 : 输出结果到控制台
System.err 是一个特殊的 PrintStream "标准"错误输出流 : 输出到控制台,在Eclipse中显示红色的
System.in 是一个特殊的InputStream "标准"输入流 : 数据源来至控制台输入
重定向 : 例如System.out 把数据输出到控制台,通过重定向可以改变输出的目的地 重定向的方法调用代码 必须写在打印或者输入的前面
System中提供对应的重定向的方法:
static void setErr(PrintStream err) 重新分配“标准”错误输出流。
static void setIn(InputStream in) 重新分配“标准”输入流。
static void setOut(PrintStream out) 重新分配“标准”输出流。
public static void main(String[] args) throws IOException { /* PrintStream 字节打印流 * PrintWriter 字符打印流 */ PrintStream ps = new PrintStream(new FileOutputStream("m.txt")); ps.print("nihao"); ps.append("shao"); ps.flush(); // nihaoshao PrintWriter pw = new PrintWriter(new FileWriter("n.txt")); pw.printf("你叫%s年龄是%d", "张三",18); // %s 表示拼接String 类型的值 %d 表示拼接int 类型的值 pw.println(); pw.append("好的"); pw.flush(); /* 输出结果: 你叫张三年龄是18 好的 */ // 标准输入输出流以及标准错误输出流 System.err.println("变红了"); //打印红色字体 System.out.println("请输入一个字符:"); int ch = System.in.read(); System.out.println(ch); /* 变红了 请输入一个字符: 2 50 */ //重定向 PrintStream ps1 = new PrintStream(new FileOutputStream("mmm.txt")); System.setErr(ps1); //重定向到指定文件中保存 System.err.print("你好"); } }
6.转换流
OutputStreamWriter:是Writer的子类。将输出的字符流转化成字节流, 即将字符流的输入对象变成字节流输入对象。
InputStreamReader:是Reader的子类。将输入的字节流转化成字符流, 即将一个字节流的输入对象变成字符流输入对象。
OutputStreamWriter流对象,它到底如何把字符转成字节输出的呢?
其实在OutputStreamWriter流中维护自己的缓冲区,当我们调用OutputStreamWriter对象的write方法时,会拿着字符到指定的码表中进行查询,把查到的字符编码值转成字节数存放到OutputStreamWriter缓冲区中。然后再调用刷新功能,或者关闭流,或者缓冲区存满后会把缓冲区中的字节数据使用字节流写到指定的文件中。
// 1.InputStreamReader类 输入的字节流转化成字符流 //创建读取文件的字节流对象 InputStream in = new FileInputStream("zz.txt"); //创建转换流对象 //这样创建对象,会避免本地默认码表读取,将不会发生解码的错误 InputStreamReader isr = new InputStreamReader(in,"utf-8"); //使用转换流去读字节流中的字节 char[] b = new char[5]; int len = -1; while((len = isr.read(b))!=-1){ System.out.println(new String(Arrays.copyOf(b, len))); } isr.close();//关闭流 // 2.OutputStreamWriter类 输出的字符流转化成字节流 //创建与文件关联的字节输出流对象 FileOutputStream fos = new FileOutputStream("yy.txt"); //创建可以把字符转成字节的转换流对象,并指定utf-8编码 OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8"); //调用转换流,把文字写出去,其实是写到转换流的缓冲区中 osw.write("你好");//写入缓冲区。 osw.flush(); osw.close(); }
7 .文本扫描器Scanner
1. 相当于一个输入流 , Java.util.Scanner 位于 util 包下。没有拓展至IO流的4个基本的抽象类,而是Object ,实现了Iterator(迭代器)接口 ,抛出 throws FileNotFoundException 。
2. Scanner文本扫描器,可以读取哪些数据?
Scanner(File source) :扫描的指定的文件
Scanner(InputStream source) :扫描指定的输入流
Scanner(String source) :扫描指定的字符串
3. 常用的方法
1:public boolean hasNextXXX():判断是否有指定类型数据,如果没有指定类型则为String
2:public XXX nextXXX():取得指定类型的数据,如果没有指定类型则为String
3:public Scanner useDelimiter(Pattren pattern):自定义分隔符
public static void main(String[] args) throws FileNotFoundException { //1. 从文件中读取数据 // next() 遇到空白字符换行 nextLine() 遇到空白字符不换行,一行一行的读。 /* Scanner sc = new Scanner(new File("aa.txt")); while(sc.hasNextLine()){ System.out.println(sc.nextLine()); } while(sc.hasNext()){ // Scanner 自带迭代器 System.out.println(sc.next()); } while(sc.hasNextInt()){ System.out.println(sc.nextInt()); } */ /*2. 从输入流中读取数据 (system.in 从控制台读取) Scanner sc1 = new Scanner(new FileInputStream("aa.txt")); while(sc.hasNextLine()){ System.out.println(sc.nextLine()); } */ //3. 从字符串中读取数据 Scanner sc2 = new Scanner("ab hao world hello fs world fs world "); System.out.println(sc2.nextLine()); while(sc2.hasNextLine()){ System.out.println(sc2.nextLine()); } //4. 使用自定义分隔符 Scanner sc3 = new Scanner("hello d-d-d-world-enen"); sc3.useDelimiter("-"); //以"-" 作为分割符,所以下面next()方法就不会以空格作为换行了。 while(sc3.hasNext()){ System.out.println(sc3.next()); } } }
8.. 随机访问文件RandomAccessFile
RandomAccessFile 类支持 “随机访问” 的方式,程序可以直接跳到文件的任意地方来读、写文件
支持只访问文件的部分内容
可以向已存在的文件后追加内容
RandomAccessFile 对象包含一个记录指针,用以标示当前读写处的位置。RandomAccessFile 类对象可以自由移动记录指针:
long getFilePointer():获取文件记录指针的当前位置
void seek(long pos):将文件记录指针定位到 pos 位置
构造器
public RandomAccessFile(File file, String mode)
public RandomAccessFile(String name, String mode)
创建 RandomAccessFile 类实例需要指定一个 mode 参数,该参数指定 RandomAccessFile 的访问模式:
r: 以只读方式打开
rw:打开以便读取和写入
rwd:打开以便读取和写入;同步文件内容的更新
rws:打开以便读取和写入;同步文件内容和元数据的更新
public static void main(String[] args) throws IOException { RandomAccessFile raf = new RandomAccessFile(new File("a.txt"),"rw"); //raf.write("javaee.hello".getBytes()); //指针默认在开始的位置 去替换 raf.seek(raf.length()); //设置和指针到文件的末尾处 raf.write("走你".getBytes()); //在末尾处添加 }
9. 复制文件的十一种方式;