流:一组有序的数据序列。
File类:文件管理
(1)File f = new File("...");
(2)f.createNewFile(); 创建文件
(3)f.isDirectory(); 是否是目录
(4)f.getCanonicalPath(); 返回路径
(5)f.exists(); 是否存在
(6)f.isFile(); f是否是文件
(7)File.separator; 分隔符
(8)f.mkdir(); 如果f是目录,则创建这个目录
(9)f.listFiles(); 返回子目录的文件对象
(10)f.delete(); 删除文件
代码示例:遍历某个目录的所有子目录:
import java.io.*;
public class StreamDemo05{
public static void main(String args[])throws Exception{
File f = new File("E:"+File.separator+"Core Java 1 practice"+File.separator+"StreamProject");
list(f);
}
public static void list(File f){
File[] files = f.listFiles();
for(File file:files){
System.out.println(file);
if(file.isDirectory()){
list(file);
}
}
}
}
InputStream和OutputStream:所有字节流的父类
InputStream提供了以下常用方法:
(1)int read(); 读取1个字节数据,然后返回0-255范围的int值,读取完为-1
注意:这里read方法中的byte转换成int和一般类型转换的byte转int是不同的,这里的int范围一定要在0-255之间。
(2)int read(byte[]b); 读取流中数据写入字节数组
(3)int read(byte[]b,int off,int len) 读取len长度的字节数,写入b的off开始的字节数组中
注意:如果考虑效率方面,则可以使用(2)(3)的方法,因为能够批量读取。
(4)void close(); 关闭流
(5)int available(); 返回此时在流中可读的字节数
(6)void skip(long n); 跳过n个字节
OutputStream提供了如下方法:
(1)write(int b); 将b先转型成byte即截取低八位字节,并写入输出流,例如如果b=257,则实际写入的只是1
(2)write(byte[]b);
(3)write(byte[]b,int off,int len);
(4)void flush();
(5)void close();
/*
本程序测试的是InputStream和OutputStream提供的read和write方法
write(int )
*/
import java.io.FileOutputStream;
import java.io.FileInputStream;
public class StreamDemo02{
public static void main(String args[])throws Exception{
FileOutputStream out = new FileOutputStream("1.txt");
int i = 257;
out.write(i);
out.close();
FileInputStream in = new FileInputStream("1.txt");
int j = in.read();
System.out.println(j);
in.close();
}
}
ByteArrayInputStream和ByteArrayOutputStream:字节数组输入流
数据源是字节数组,
ByteArrayInputStream(byte[] buf, int offset, int length)
ByteArrayInputStream(byte[] buf)
以上的buf就是这个输入流的数据源。
ByteArrayOutputStream out = newByteArrayOutputStream();
byte[] b = out.toByteArray();获得输出流的字节数组。
当然然后可以通过:
ByteArrayInputStream in = new ByteArrayInputStream(b);把写入的字节数组导入输出流
import java.io.*;
public class ByteArrayInputStreamDemo01{
public static void main(String args[])throws Exception{
byte[]b = {-1,0,1};
ByteArrayInputStream in = new ByteArrayInputStream(b);
int data=0;
while((data=in.read())!=-1){
byte tmp = (byte)data;
System.out.println(tmp);
}
in.close();
}
}
PipedInputStream和PipedOutputStream:管道流
管道输入流从特定的管道输出流中读取数据,read( )方法在没有数据可读的情况下会阻塞并等待,直到有数据可读才继续读。
PipedOutputStream out = new PipedOutputStream();
PipedInputStream in = new PipedInputStream(out);
就建立好了连接。
import java.io.*;
import java.util.*;
public class PipedInputStreamDemo{
public static void main(String args[]){
Sender sender = new Sender();
Receiver receiver = new Receiver(sender);
Thread t1 = new Thread(sender);
Thread t2 = new Thread(receiver);
t1.start();
t2.start();
}
}
class Sender implements Runnable{
private PipedOutputStream out = new PipedOutputStream();
public void run(){
try{
for(int i=-127;i<=128;i++){
out.write(i);
Thread.sleep(2000);
}
out.close();
}
catch(Exception e){
e.printStackTrace();
}
}
public PipedOutputStream getStream(){
return out;
}
}
class Receiver implements Runnable{
private PipedInputStream in;
public Receiver(Sender sender){
try{
in = new PipedInputStream(sender.getStream());
}
catch(Exception e){
e.printStackTrace();
}
}
public void run(){
try{
int data;
while((data=in.read())!=-1){
System.out.println(data);
}
in.close();
}
catch(Exception e){
e.printStackTrace();
}
}
}
SequenceInputStream:顺序流
将多个输入流合并作为一个输入流。
SequenceInputStream(InputStream in1,InputStream in2); 按照in1和in2的顺序读取,外界看来好像一个输入流。
import java.io.*;
public class SequenceInputStreamDemo01{
public static void main(String args[])throws Exception{
ByteArrayInputStream in1 = new ByteArrayInputStream("x".getBytes());
ByteArrayInputStream in2 = new ByteArrayInputStream("zg".getBytes());
SequenceInputStream in = new SequenceInputStream(in1,in2);
int data = 0;
while((data=in.read())!=-1){
System.out.println(data);
}
in.close();
}
}
FileInoutStream和FileOutputStream:文件流
(1) FileInputStream in = new FileInputStream("1.txt");
(2) FileOutputStream out = new FileOutputStream("1.txt");
特点:在InputStream和OutputStream的基础上增加了文件读取,但是只能读取字节或字节数组。
还可以设置追加数据。
import java.io.*;
public class StreamDemo03{
public static void main(String args[])throws Exception{
FileOutputStream fos = new FileOutputStream("1.txt");
DataOutputStream out = new DataOutputStream(fos);
out.writeBytes("abc");
fos.close();
out.close();
FileInputStream fin = new FileInputStream("1.txt");
DataInputStream in = new DataInputStream(fin);
byte[]b = new byte[1024];
int len = in.read(b);
String str = new String(b,"UTF-8");
String result = str.trim();
System.out.println(result);
in.close();
fin.close();
}
}
代码2:拷贝文件
import java.io.*;
public class Copy{
public static void main(String args[])throws Exception{
FileInputStream in = null;
FileOutputStream out = null;
in = new FileInputStream(args[0]);
out = new FileOutputStream(args[1]);
int tmp = 0;
while((tmp=in.read())!=-1){
out.write(tmp);
}
out.close();
in.close();
}
}
FilterInputStream:过滤输入流
主要应用装饰器类,用于增加一些功能。
BufferedInputStream和BufferedOutputStream:缓冲流
作为过滤流的中间层,用以手动构建缓冲区。
DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("1.txt")));
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("1.txt")));
Output:先将数据写入缓冲区,当缓冲区满时,写入数据汇。
因此必须使用完就close。
DataInputStream和DataOutputStream:读取数值类型流
实现了DataInput和DataOutput接口的类。
DataInput提供了如下方法:
(1)Xxx readXxx();读取基本数据类型
(2)int read(byte[]b);读取至字节数组中,返回实际读取的长度
(3)readChar()读取一个字符即两个字节
(4)String readUTF();
注意:不能使用readLine()方法!因为已过时。
DataOutput提供了如下方法:
(1)void wrtieXxx(Xxx )写入基本数据类型
(2)void writeBytes(String)能够以字节方式写入String,随后可以用read读取。
(3)void writeChars(String)以字符方式写入,一个字符是两个字节
(4)void writeUTF(String );
Unicode统一采用2个字节编码,UTF-8是Unicode的改进,原本ASCII码的字符还是一个字节。
import java.io.*;
public class DataInputStreamDemo01{
public static void main(String args[])throws Exception{
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("data.txt")));
out.writeUTF("我ai中国");
out.close();
DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("data.txt")));
String str = in.readUTF();
System.out.println(str);
in.close();
}
}
PrintStream:打印流 //装饰器
PrintStream out = new PrintStream(OutputStream o,boolean autoflush);
out.print(Xxx);
out.println(Xxx);
PushBackInputStream:具有回退的功能。
ObjectInputStream和ObjectOutputStream:对象流
实现了DataInput和DataOutput接口
对于对象:
(1)writeObject(Object);
(2)Object readObject(); 读取时需要强制类型转换
对于基本类型:使用readXxx和writeXxx方法
过滤流 :分层思想
由于一种单一的流的功能是有限的,因此如果能够把多个流结合起来,则会拓宽功能。
RandomAccessFile:随机存取流
实现了DataInput和DataOutput接口。
提供了如下方法:
(1)RandomAccessFile raf = new RandomAccessFile("file","r或者rw");
(2)raf.seek(long pos); 把文件指针设定在pos处
(3)long raf.getFilePointer():返回文件指针
(4)long raf.length();返回长度
(5)raf.skipBytes(long);
import java.io.*;
import java.util.*;
public class StreamDemo04{
public static void main(String args[])throws Exception{
RandomAccessFile out = new RandomAccessFile("1.txt","rw");
Employee[]e = new Employee[3];
e[0] = new Employee("张三",1000.0,1991,2,1);
e[1] = new Employee("xiazdong",2000.0,1991,8,12);
e[2] = new Employee("李四",3000.0,1889,3,2);
e[0].writeData(out);
e[1].writeData(out);
e[2].writeData(out);
out.close();
RandomAccessFile in = new RandomAccessFile("1.txt","r");
in.seek(20*2+8+12);
Employee result = new Employee();
result.readData(in);
System.out.println(result);
in.close();
}
}
class Employee{
/*
name = 20;
salary = 8;
hireDay = 12;
*/
private String name;
private double salary;
private Date hireDay;
private static final int NAME_LENGTH = 20;
public Employee(){
}
public Employee(String name,double salary,int year,int month,int day){
while(name.length()<NAME_LENGTH){
name +="\u0000";
}
if(name.length()>NAME_LENGTH){
name = name.substring(0,NAME_LENGTH);
}
this.name = name;
this.salary = salary;
GregorianCalendar calendar = new GregorianCalendar(year,month-1,day);
this.hireDay = calendar.getTime();
}
public String getName(){
return name;
}
public double getSalary(){
return salary;
}
public Date getHireDay(){
return hireDay;
}
public String toString(){
return "name="+name.trim()+",salary="+salary;
}
public void writeData(DataOutput out)throws Exception{
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(hireDay);
int y = calendar.get(Calendar.YEAR);
int m = calendar.get(Calendar.MONTH);
int d = calendar.get(Calendar.DAY_OF_MONTH)+1;
out.writeChars(name);
out.writeDouble(salary); //8
out.writeInt(y);
out.writeInt(m);
out.writeInt(d);
}
public void readData(RandomAccessFile in) throws Exception{
StringBuffer n = new StringBuffer();
for(int i=0;i<NAME_LENGTH;i++){
n.append(in.readChar());
}
double s = in.readDouble();
int y = in.readInt();
int m = in.readInt();
int d = in.readInt();
String str = n.toString();
System.out.println(str);
GregorianCalendar calendar = new GregorianCalendar(y,m-1,d);
this.hireDay = calendar.getTime();
this.name = str;
this.salary = s;
}
}
Reader和Writer:字符流的父类
一个字符是2个字节,在字符流中,每次读取的最小单位就是一个字符。
Writer:把内存中的Unicode字符转换成其他编码类型的字符,然后写到输出流
(1)write(String) 写入字符串
Reader:将输入流中采用其他编码类型的字符转换成Unicode字符。
(1)int read(char[]ch); 读取字符数组 然后用String.valaueOf(ch);转换成String
(2)char ch = (char)in.read(); 每次读取一个字符
CharArrayReader和CharArrayWriter
CharArrayReader:字符数组为数据源
CharArrayReader in = new CharArrayReader(char[]ch);
import java.io.*;
public class CharArrayReaderDemo01{
public static void main(String args[])throws Exception{
char[]ch = {'a','b','我'};
CharArrayReader in = new CharArrayReader(ch);
int data;
while((data=in.read())!=-1){
System.out.println((char)data);
}
}
}
CharArrayWriter:字符数组为数据汇
CharArrayWriter out = new CharArrayWriter();
out.write();
char[]ch = out.toCharArray();
import java.io.*;
public class CharArrayWriterDemo{
public static void main(String args[]){
CharArrayWriter out = new CharArrayWriter();
out.write('你');
out.write('好');
char[]ch = out.toCharArray();
System.out.println(ch);
}
}
StringReader 和StringWriter
StringReader :字符串为数据源
StringReader in = new StringReader(String);
StringWriter:以字符串为数据汇
StringWriter out = new StringWriter();
String str = out.toString();
InputStreamReader和InputStreamWriter
InputStreamReader:以字节流为数据源
InputStreamReader in2 = new InputStreamReader(new FileInputStream("Reader.txt"),"UTF-8");
以上语句指定输入流FileInputStream为数据源,并假定数据源是UTF-8编码,每次读取一个UTF-8字符,转换成Unicode字符。
通常InputStreamReader被BufferedReader包装。
InputStreamReader in1 = new InputStreamReader(new FileInputStream("writer.txt"),"UTF-8");
BufferedReader in = new BufferedReader(in1);
in.readLine();
OutputStreamWriter:以字节流为数据汇
把Unicode编码转换成特定的编码。
通常OutputStreamWriter被BufferedWriter,PrintWriter包装。
OutputStreamWriter out1 = new OutputStreamWriter(new FileOutputStream("writer.txt"),"UTF-8");
BufferedWriter bw = new BufferedWriter(out1);
PrintWriter out = new PrintWriter(bw,true);
out.println():
FileReader:InputStreamReader的子类,但是只能读取默认编码的数据文件。
FileReader in = new FileReader(String);
FileWriter:OutputStreamWriter的子类,只能写入默认编码的数据文件。
BufferedReader:让Reader能够有缓冲区
BufferedReader in = new BufferedReader(Reader i);
in.readLine();
PrintWriter和Scanner
PrintWriter写入文本数据
构造方法:
(1)PrintWriter(Writer out, boolean autoFlush)
常用方法:
(1)print(X) 参数可以是基本数据类型,String
(2)println(X) 参数可以是基本数据类型,String
代码示例:写入和读取Employee对象
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Date;
import java.io.PrintWriter;
import java.io.BufferedReader;
import java.io.Writer;
import java.io.Reader;
import java.io.FileWriter;
import java.io.FileReader;
import java.util.StringTokenizer;
public class StreamDemo01{
public static void main(String args[])throws Exception{
Poxy p = new Poxy();
p.write();
p.read();
}
}
class Poxy{
private Employee[] emp;
public Poxy() throws Exception{
Employee e[] = new Employee[3];
System.out.println("***********创建人物***********");
e[0] = new Employee("张三",1000.0,1991,8,12);
e[1] = new Employee("李四",2000.0,1992,3,1);
e[2] = new Employee("王五",3000.0,1990,1,1);
emp = e;
}
public void write()throws Exception{
PrintWriter out = null;
out = new PrintWriter(new FileWriter("data.txt"),true);
System.out.println("*********开始写入数据*********");
emp[0].writeData(out);
emp[1].writeData(out);
emp[2].writeData(out);
System.out.println("***********写入完毕**********");
out.close();
}
public void read()throws Exception{
System.out.println("**********开始读取***********");
BufferedReader in = null;
in = new BufferedReader(new FileReader("data.txt"));
Employee[] result = new Employee[3];
result[0] = new Employee();
result[1] = new Employee();
result[2] = new Employee();
result[0].readData(in);
result[1].readData(in);
result[2].readData(in);
System.out.println(result[0]);
System.out.println(result[1]);
System.out.println(result[2]);
System.out.println("**********读取完毕***********");
in.close();
}
}
class Employee{
private String name;
private double salary;
private Date hireDay;
public Employee(){
}
public Employee(String name,double salary,int year,int month,int day){
this.name = name;
this.salary = salary;
GregorianCalendar calendar = new GregorianCalendar(year,month-1,day);
this.hireDay = calendar.getTime();
}
public String getName(){
return name;
}
public double getSalary(){
return salary;
}
public Date getHireDay(){
return hireDay;
}
public String toString(){
return "name="+name+",salary="+salary;
}
public void writeData(PrintWriter out)throws Exception{
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(getHireDay());
int year = calendar.get(Calendar.YEAR);
int month = (calendar.get(Calendar.MONTH)+1);
int day = calendar.get(Calendar.DAY_OF_MONTH);
out.println(this.getName()+"|"+this.getSalary()+"|"+year+"|"+month+"|"+day);
}
public void readData(BufferedReader in) throws Exception{
String line = null;
line = in.readLine();
StringTokenizer token = new StringTokenizer(line,"|");
this.name = token.nextToken();
this.salary = Double.parseDouble(token.nextToken());
int y = Integer.parseInt(token.nextToken());
int m = Integer.parseInt(token.nextToken());
int d = Integer.parseInt(token.nextToken());
GregorianCalendar cal = new GregorianCalendar(y,m-1,d);
this.hireDay = cal.getTime();
}
}
Scanner读取文本数据
构造方法:
(1)Scanner(InputStream source)
(2)Scanner(File source,String charsetName)
常用方法:
(1)nextXxx();读取基本类型
(2)nextLine(); 读取一行
(3)读取直到出现标记:
useDelimiter(String str);用str作为标记
String next();读取到下一个标记为止
字节流和字符流的区别:
字符流使用了缓存,所有内容存入缓冲区,需要刷新缓冲区,把所有内容输出。
字节流没有使用缓存,在字节流操作中,即使没有关闭,最终也会输出。
在所有硬盘上保存文件或是进行传输的时候都是以字节的方式进行的,包括图片都是字节完成,字符只有在内存中才会形成,所以字节是最多的。
边读边写的开发方式。
装饰器设计模式:
如果想要扩展一个流的功能一般采用继承的方式扩展,但是这种方式会使得流的层次更加复杂,因此有没有什么好办法呢?
装饰器的设计模式就解决了这个问题,只需要单单把扩展功能放在装饰器中,再提供了Decorator d = new Decorator(InputStream in)的构造方法即可。这样可以提高代码的重用性。
String类的常用方法:
getBytes("encode");比如getBytes("UTF-8");
String str = new String(byte[],"encode");
标准IO:
特点:是由jVM创造出来的,因此存在于程序的整个生命周期中。
(1)System.in:标准输入,默认为键盘。
(2)System.out:标准输出,默认为console.
(3)System.err:错误输出。
System.out和System.err的区别:
System.out打印的信息是专门给用户看的,而System.err的信息属于后台信息,不应该给用户看。
设置标准输入输出:
System.setIn(InputStream);
System.setOut(PrintStream);
InputStream in = new FileInputStream("test.txt");
PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream("out.txt")));
import java.io.*;
public class Redirector{
public static void main(String args[])throws Exception{
InputStream standardIn = System.in;
PrintStream standardOut = System.out;
InputStream in = new FileInputStream("test.txt");
PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream("out.txt")));
redirect(in,out);
copy();
in.close();
out.close();
}
public static void redirect(InputStream in,PrintStream out){
System.setIn(in);
System.setOut(out);
}
public static void copy()throws Exception{
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader in = new BufferedReader(isr); //包装System.in
String line;
while((line=in.readLine())!=null){
System.out.println(line);
}
in.close();
}
}