IO/输出输入
File类:
File类是包IO包中唯一代表磁盘文件本身对象,File类定义了一些与平台无关的操作文件。通过,File类提供的各种方法,我们创建。删除文件、重命名文件、判断文件的读写权限及是否存在。设置和查询最近修改时间。
在java中目录也被当着File使用。只是多了一些特有的功能。可以使用list方法列出目录文件名
判断某个文件是否存在、存在则删除、不存在刚创建。
import java.io.*; public class FileTest { public static void main(String[] args) { File f=new File("c:\\1.txt"); if(f.exists()) f.delete(); else try { f.createNewFile(); } catch(Exception e) { System.out.println(e.getMessage()); } yywrSystem.out.println("File name:"+f.getName()); System.out.println("File path:"+f.getPath()); System.out.println("Abs path:"+f.getAbsolutePath()); System.out.println("Parent :"+f.getParent()); System.out.println(f.exists()?"exists":"does not exist"); System.out.println(f.canWrite()?"is writeable":"is not writeable"); System.out,println(f.canRead()?"is readable":"is not"+"a directory"); System.out.println(f.isDirectory()?"is":"is not"+" a directory"); System.out.println(f.isFile()?"is normal file": might be anamedpipe); System.out.println(f.isAbsolute()?"is absolute":"isnot absolute"); System.out.println("File last modified:"+f.lastModified()); System.out.println("File size:"+f.length()+" Bytes"); } }
delete方法删除由File对象 的路径所表示 的磁盘文件或目录,如果 删除的是目录那么其中的内容必须为空
RandomAccessFile类:
RandomAccessFile可是一个文件访问类支持随机访问方式,我们可以跳转到文件的任意位置处读写数据。不想把文件从开始读到尾就可以用这种方式
RandomAccessFile对象 类有个位置指示器。指向当前读写处的位置,文件指示器一打开会出现开头处,我们可以移动文件指示器到新的位置,随后读写操作从新的位置开始
RandomAccessFile可以只读或 读写方式打开打开文件,具体的取决于我们创建RandomAcceddFile对象的构造方式:
new RandomAcceddFile(f,"rw");//读写方式 new RandomAcceddFile(f,"r");//只读方式 注意:当我们的程序需要以读写的方式打开一个文件时,如果这个文件不存在,程序会自动创建
设计一个类来封装员工信息
import java.io.*; public class RandomFileTest { public static void main(String[] args)throws Exception { Employee e1=new Employee("zhangsan",23); Employee e2=new Employee("lisi",25); Employee e3=new Employee("wangwu",24); RandomAccessFile ra=new RandomAccessFile("c:\\1.txt","rw"); ra.write(e1.name.getBytes()); ra.write(e1.age); ra.write(e2.name.getBytes()); ra.write(e2.age); ra.write(e3.name.getBytes()); ra.writeInt(e3.age); ra.close(); RandomAccessFile raf=new RandomAccessFile("c:\\1.txt","r"); int len=8; raf.skipBytes(12);//跳过第一个员工的信息,其中姓名 八个字节 年龄4个字节 System.out.println("第二个员工信息: "); String str=" "; for(int i=0;i<len;i++) str=str+(char)raf.readByte(); System.out.println("name"+str); System.out.println("age: "+raf.readInt()); System.out.println("第一个员工信息: "); raf.seek(0);//将文件指针移动到文件开始位置 str=" "; for (int i=0;i<len;i++) str=str+(char)raf.readByte(); System.out.println("name: "+str); System.out.println("age: "+raf.readInt()); System.out.println("第三个员工信息: "); raf.skipBytes(12);//跳过第二个员工信息 str=" "; for (int i=0;i<len; i++) str=str+(char)raf.readByte(); System.out.println("name: "+str.trim()); System.out.println("age: "+raf.readInt()); raf.close(); } } class Employee { String name; int age; final static int LEN=8; public Employee(String name, int age) { if (name.length()>LEN) { name=name.substring(0,8); } else { while (name.length()<LEN) name=name+"\u0000"; } this.name=name; this.age=age; } }
这就是一个RandomAccessFile存储数据和读入数据的操作。这里面的那个文件如果不存在的话那么就会自动创建一下
如果说报eof基本上或者大部分都是读的比写的多才会抛的,至于其他的情况比较少见比如说我这里这个就报了这样的错误
节点流:
理解流的概念:
流就像队列一样:数据流是一串连续不断的数据的集合,就像水管里的水一样,在水管 的一端一点一点地供水而在另一端看到的是一股连续不断的水流,数据定稿程序可以是一段一段地向数据流管道中写入数据,数据段会按先后顺序形成一个长的数据流。
我们将IO流为舂为两个大类,节点流类和过滤流(也叫处理流类)程序直接操作目标设备对应的类叫节点流类
程序也可以通过一个间接流类去调用节点流类,以达到更加灵活方便地读写各种类型的数据。这个间接的类就是过滤流类(也叫处理流类。)
IputStream与OutputStream:
程序可以从中连续取字节的对象 叫输入流 用InputStream类
程序能向其中连续写入字节的对象叫输出流 用OutputStream类完成 InputSream和OutputStream这两个类都是抽象类。因为不能知道他们所对应的具体的IO设备
将节点流类所对应的IO源和目标称为字流节点。
InputStream定义了java的输入流模型。应该方法遇到错误会报IOException
int read()返回 下一个输入字节 的整型,如果返回-1那么就表示遇到流的末尾了结束
int read(byte[] b)读入b.length个放到b中并返回实际读入的字节 数
int read(byte[] b,int off,int len)这个方法表示把流中的数据读到数组b中从角标为off开始的len个数组元素。
long skip(long n)跳过输入流上的n个字节并返回实际读入的字节数。
int availabale()返回当前输入流中可读的字节数
void mark(int readlimit)在输入流的当前位置处放上一个标志,允许 最多再读入readlimit个字节。
void reset()把输入指针返回 到以前所做的标志处
boolean markSupported()如果当前流支持mark/reset操作就返回 true
void close()在操作完一个流后要使用此方法将其关闭,系统就会释放与这个流相关的资源
IputStream是一个抽象 类。程序中实际使用的是他的子类对象,不是所有子类 都 会支持IputStream中定义的某些方法的,
一个对象 在没有引用 变量指向它时会变成 垃圾,最终会被 垃圾回收器从内存中清除。
outputStream是一个定义 了输出流的抽象类,这个类中的所有方法 均返回void并在遇到错误 时引发IOException
void write(int b)将一个字节写入到输出流、注意这里参数都是int型的,它允许write使用表达示而不用强制转换成byte型
void write(byte[]b)将整个字节数组写到输出流中
void write(byte[]b,int off, int len)将字节数组b中的从off开始的len个字节写到输出流
void flush 彻底完成输出 并清空缓冲区
void clos 关闭输出流
FilelnpurStream与FileOutputSream:
这两个流节点用来操作磁盘文件,在创建一个FileIputStream对象时通过构造函数指定文件的路径和名字,当然这个文件应当是存在的和可读的在创建一个FileOutputStream对象时指定文件如果存在将要被 覆盖
同一磁盘文件FileInputStream对象的两种 方式,其实 用到的两个构造函数会引发FileNotFoundException异常
FileInputStream inOne=new FilInputStream("hello.test");
File f= new File("hello.test");
FileInputStream inTwo= new FileInputStream(f);
利用FileOutputStream类向文件写入字符串利用FileInputStream读出
improt java.io.*; public class FileSream { public static void main(String[] args) { File f=new File("hello.txt"); try { FileOutputStream out=new FileOutputStream(f);//将代码中的所有FileOutputStream改写成FileRead byte buf[]="www.it315.org".getBytes(); out.write(buf); out.close(); } catch(Exception e) { System.out.println(e.getMessage); } try { FlieInputStream in= new FlieInputStream(f); byte [] buf=new byte[1024]; int len=in.read(buf); System.out.println(new String(buf,0,len)); } catch(Exception e) { System.out.println(e.getMessage()); } } }
这里如果没有这个文件那么会自动生成这个文件如果没有指定磁盘那么就会在java源文件那个磁盘自动自成
Reader与Writer
这是两个管理字符输入输出的类他们与前面的InputStream和OutputStream(他们两个管理字节流)相对应也同样的是两个抽象类
FileReader文件读取和FileWriter文件输入 下面我们将上面的代码改成使用Reader与Writer的方式
其实 他们功能都是相似的 所以只需要把这两个类相替换就可以了
PipedInputStream与PipedOutputStream
一个PipedInputStream对象必须和一个PipedOutputStream对象进行连接产生一个信息管道PipedOutputStream可以向管理中定入数据PipedInputStream再从管道中读取数据
这两个类就是用来完成线程间通信的。
其实管道流类,可以实现各个 程序模块之间的松耦合通信,可以用来将多个这样的模块输出 流与输入 流相连接,以做成各种应用 程序
管道流进行通信 的模块具有“强内聚 弱耦合”这样一个模块被弄下去了不会影响到其他模块
ByteArrayInputStream与ByteArrayOutputStream:
ByteArrayInputStream是输入流的一种实现,有两个构造函数
1.ByteArrayInputStream(Byte[] buf) 2.ByteArrayInputStream(byte[ ] buf, int offset , int length)
第二个构造函数指定数组buf中从offset开始的length个元素做为数据源
ByteArrayOutputStream是输出流的一种实现有两个构造函数
1.ByteArrayOutputStream () 2.ByteArrayOutputStream(int)
第一种形式的构造函数创建一个32【字节的缓冲区,第二种形式根据参数指定 的大小创建缓冲区,缓冲区的大小 在数据过多时自动增长
将输入流中的英文字母变成大写字母 写入到输出流中
import java.io.*; public class ByteArragTest { public static void main(String[] args)throws Exception { String tmp="abcdefghijklmnopqrstuvwxyz"; byte [ ]src =tep.getByte();//src为转换前的内存块 ByteArrayInputStream input=new ByteArrayInputStream (src); ByteArrayOutputStream output= new ByteArrayOutputStream(); new ByteArrayTest().transform(input,output); } public void transform(InputStream in,OutputStream out) { int c=0; try { while((c=in.read())!=-1)//read在读到了流的结尾处返回-1 { int C =(int)Character.toUpperCase((char)c); out.write(C); } } catch(Exception e) { e.printStrackTrace(); } } }
ByteArrayOutputStream和ByteArrayInputStream类对应的字符串读写类分别是StringReader和StringWriter
IO的复用性:
如果一个文件专用于存储 文本字符的数据,没有包含字符之外的其他数据,我们就称【之类文本文件,除此之外的文件就是二进制文件,
为了支持输入输出 设备java定义 了两个特殊的流对象。System.in和System.out。
System.in 这个是对应 键盘 是InputSystem类型的,程序使用System.in就可以读取键盘输入的数据
System.out对应显示器是PrintStream类型的PrintStream是OutputStream的一个子类程序使用这个东东可以将数据显示到显示器上
上面的一个例子有一个不好的地方就是那个什么的输出转化为大写的字符串是固定的
这里我们就来做一个利用键盘输入数据通过大写显示出来的小程序
import java.io.*; public class ByteArrayTest { public static void(String[ ] args)thrwos Exception { new ByteArrayTest().transform(System.in,System.out); } public void transfrom(InputStream in,OutputStream out) { int c=0; try { while((c=in.read())!=-1) { int C=(int)Character.toUpperCase((char)c); out.write(C); } } catch(Exception e) { e.printStackTrace(); } } }
过滤流与包装类:
简单的说中间类或者说处理流类就是包装类
我们可以用包装类去包装另外一个包装类,创建包装类对象 时,必须指定它要调用 的那个底层流对象,也就是这些包装类的构造函数中,都 必须 接收另外一个流对象 作为参数。就好比 DataOutputStream包装类的构造函数是
public DataOutputStream(OutputStream out)
参数Out就是DataOutputStream要调用 的那个底层输出 流对象
BufferedInputStream 与 BufferedOutputStream:
对I/O进行缓冲是一种常见的性能优化,缓冲流为I/O流增加了内存缓冲区,主要的目的:
1.允许java的I/O一次不只操作一个字节,这样提高了整个系统性能
2.有了缓冲区使得在流上执行skp、mark、reset方法都成为可能。
BufferedInputStream
BufferedInputStream的两个构造函数:
BufferedInputStream(InputStream in)构造函数创建了一个带有32字节缓冲区的缓冲流
BufferedInputStream(InputStream in,int size)构造函数指定大小来创建缓冲区
可 以说他们和数组输入输出流是一样的
mark只能限制在建立的缓冲区内
BufferedOutputStream
其实BufferedOutputStream输出和OutputStream输出完全一样只不过BufferedOutputStream有一个fliush方法用来将缓冲区的数据强制输出完。
有两上构造函数: BufferedOutputStream(OutputStream out) BufferedOutputStream(OutputStream out, int size) 构造函数不解释
DataInputStream与DataOutputStream:
DataInputStream类提供了3种写入字符串的方法:
1.public final void writeBytes(String s)throws IOException
writeBytes只将字符串中的每个字符的低字节的内容写入目标设备中
2.public final void writeCahrs(String s)throws IOException
writeChars将字符串中的每一个字符的两个字节的内容都写入到目标设备中
3.public final void writeUTF(String s)throws IOException
UTF编码规则:
1.c的范围在\u0001或其范围\u007f对应的UTF码是一个字节内容(byte)c
2.c是\u0000或其在\u0080和\u07ff之间的utf对应的是两个字节内容为(byte)(0xc0|(0xf&(c>>6))),(byte)(0x80|(0x3f&c))
3.c的范围在\u0800和ufff之间。对应UTF占三个字节内容为(byte)(0xc0|(0x0f&(c>>12))),(byte)(0x80|(0x3f&(c>>6))),(byte)(0x80|(0x3f&c))
采用多个流对象来进行文件的读写
import java.io.*; public class DataStreamTest { public static void main(Stirng [] args) { try { FileOutputStream fos= new FileOutputStream("hello.txt"); BufferedOutputStream bos=new bufferedOutputStream(fos); DataOutputStream bos=new DataOutputStream(bos); dos.writeUTF("ab中国"); dos.writeBytes("ab中国"); dos.writeChars("ab中国"); dos.close(); FileInputStream fis= new FileInputStream("hello.txt"); BufferedInputStream bis=new bufferedInputStream(fis); DataInputStream bis=new DataInputStream(bis); System.out.println(dis.readUTF()); /*byte [] buf=new byte[1024]; int len=dis.read(buf); System.out.println(new String(buf,0,len));*/ fis.close(); } catch(Exception e) { System.out.println(e.getMessage()); } } }
PrintStream:
PrintStream类提供了print和println方法可以实现基本数据类型的格式化成字符串 而且这个对象具有多个重载的print和println方法,它们可输出各种类型(包括对象)的数据
PrintStream有三个构造函数: PrintStream(OutputStream out) PrintStream(OutputStream out,boolean auoflush)
PrintStream(OutputStream out,boolean auoflush,String encoding)
其中auoflush控制在java中遇到换行符(\n)时是否自动清空缓冲区,encoding是指定编码方式
IO包中提供了一个与PrintStream类相似的PrintWriter类,这个是即使遇到换行符也不会自动清空清空缓冲区
格式化时应当注意ASCII
ObjectInputStream和ObjectOutputStream:
这两个类是用于存储和读取对象的输入和输出流类,我们只要把对象 中的所有成员变量都 存储 起来就等 于保存了这个对象,读取一个对象 中原来 保存的所有成员变量的取值就是读取 一个对象 ObjectInputStream与ObjectOutputStream就可以完成 保存和读取对象 成员变量取值过程的,但是读写或存储对象 必须实现 Serializable接口,Serializable接口中没有定义任何 方法只是一下标记。ObjectInputStream与ObjectOutputStream类不会保存和读取对象中的transient和static类型的成员变量,使用ObjectInputStream与ObjectOutputStream类保存和读取对象的机制叫序列化
下面我就做一个这个类吧
public class MyClass implements Serializable { public transient Thread t;//这里成员变量不会被保存和读取 pricate String customerID; private int tota1; } 序列化的好处: 它可以将任何实现了Serializable接口对象转换为连续的字节数据 ,这些数据仍可被还原为原来 对象 状态,
创建一个学生对象,并把输出 到一个文件(mytest.txt)中再把这个对象读出来
import java.io.*; public class serialization { public static void main(String args[]) throws IOException,ClassNotFoundException { student stu=new Student(19,"dintdding",50,"huaxue"); FileOutputStream fos=new FileOutputStream("mytest.txt"); ObjectOutputStream os=new ObjectOutputStream(fos); try { os.writeObject(stu); os.close(); } catch(IOException e) { System.out.println(e.getMessage); } stu=null; FileInputStream fi=new FileInputStream("mytest.txt"); try { stu(student)si.readObject(); si.close(); } catch(IOException e) { System.out.println(e.getMessage()); } System.out.println("ID is:"+stu.id); System.out.println("name is:"+stu.name); System.out.println("age is"+stu.age); System.out.println("department is:"+stu.department); } } class student implements Serializable { int id; String name; int age; String department; public student(int id,String name,int age,String department) { this.id=id; this.name=name; this.age=age; this.department=department; } }
字节流与字符流的转换:
InputStreamReader和OutputStreamReader 这两个类是字节流和字符 流之间的转换类。InputStreamReader可以将一个字节 流的字节 解码成字符OutputStreamReader将写入字符编码成字节后写入一个字节 流
InputStreamReader主要有两个构造函数
InputStreamReader(InputStream in) //用默认字符集创建 一个InputStreamReader对象
InputStreamReader(InputStream in, StringCharsetName)//接受以指定字符集名的字符串 并用该 字符集创建对象
OutputStreamWriter也有两个对应的构造函数
OutputStreamWriter(OutputStream in)//用默认的字符集创建 一个OutputStreamWriter对象
OutputStreamWriter(OutputStream in,String CharsetName)//接受指定字符集名的字符串并用该字符创建对象
在实际操作中建议多多的使用BufferedWriter类包装OutputStreamWriter类和InputStreamReader
BufferedWriter out =new BufferedWriter(new OutputStreamWriter(System.ou))
BufferedReader in=new BufferedReader(new InputStreamReader(System.in))
构建BuffereReader对象时必须传递一个Reader类型的对象作为为参数而键盘对应的System.in是一个InputStream类型的对象
BuffereRreader类可以读取一行文本,对应的BuffferedWriter
FileWriter和FileReader都是包装类,FileReader是InputStreamReader子类,FileWriter是OutputStreamWriter的子类
字符集的编码问题:
第一个字符都用一个数字来表示,实际上表示这些字符的数字的字节最高位bit都为0也就是说这些数字都在0-127之间。就好比a对应 的是97,b对应 的是98这种固定的字符与数字对应 的编码规则叫做ASCII(美国标准信息交换码)
然后为了在中国方便使用 将一个中文字符与两个ASCII字符相区别,中文的每个字节(bit) 都为1 这样的标准编码固定了下来的规则叫做GBK(国际码)
然后又来了一个全世界的符号统一编码 Unicode编码
import java.io.*; public class InputReader { public static void main(String [ ] args)throws Exception { InputStreamReader isr=new (System.in,"iso8859-1")//也可以是InputStream isr=new InputStreamReader(System.in,"gb2312") BufferedReader br=new BufferedReader(isr); String strLine =br.readLine() for(int i=0;i<strLine.length();i++) { System.out.println(Integer.toHexString((int)strLine.charAt(i))); } isr.close(); System.out.println(strLine); } }
这里手动的在控制台输入中国然后print出他对应 的十六进制
Decorator设计模式:
通过包装类就可以用一个对象(the Decorators)包装类另外的一个对象
Execpetion类从Throwable类继承的三个printStackTrace
public void printlnStackTrace()
public void printlnStackTrace(PrintStream s)
public void printlnStackTrace(PrintStream s)
把异常信息打印到屏幕上
import java.io.*; public class TestPrintWriter { public static void main(String [ ] args) { try { throw new Exception("test"); } catch(Exception e) { StringWriter sw=new StringWriter(); e.printStackTrace(new PrintWriter(sw)); String strException =sw.toString(); System.out.pritnln(strException); } } }