IO
来源:互联网 发布:php产品授权系统 编辑:程序博客网 时间:2024/06/10 05:10
IO/输入与输出:
JDK定义很多IO类,放在了JDK的API中的java.io包中。常用的包括一下几种:
A. File类 :是IO包中唯一代表磁盘本身信息的类,而不是文件中的内容。里面的方法就是看这个文件的属性。
B. RandomAccessFile类:提供了众多的文件访问方法。还支持“随机访问”方式。
优势
随机读写等长记录格式的文件。
只能够操作文件,不能访问其他的IO设备,如网络,内存映射等。
两种构造方法:new RandomAccessFile(f,”rw”)//读写方式
new RandomAccessFile(f,”r”)//只读方式
C. 各种节点流类:
流的概念:流是字节序列的抽象概念。文件是数据的静态存储形态,而流是指数据 传输时的形态。
流类分为两类:节点流类和过滤流类(处理流类)。
InputStream类:程序可以从中连续读取字节的对象叫输入流,抽象类。
方法: int read(),如果结束 int的return值为-1。容易发生阻塞。
该方法只读了一个字节的数据,把该数据放入到返回值的低字节位, 高字节位补零。重载方法 int read(byte[] b),int read(byte[] b,off,int,len) long skip(long n) 用在包装类中
int available() 返回当前字节流中可读的字节数。防止发生阻塞,占CPU 的资源。
void mark(int readlimit)
void reset() 与mark方法配合使用。
boolean markSupported()
void close()
思考题:有了垃圾回收器,为什么还有调用close方法?
垃圾回收器只能管理Java资源,而不能管理操作系统中的资源,而在创 建java实例对象的同时,操作系统创建了系统资源,因此需要靠close方法来关闭 系统资源。
OutputStream类:程序可以向其中连续写入字节的对象叫输入流,抽象类。
方法:void write(int b) 将一个整数的最低字节位的数据写入输入流。
重载方法:viod write(byte[] b),void write(byte[] b,int,off,len)
viod flush()
viod close() 用于将内存缓冲区的彻底内容清空,并输出到目标的IO设备 上。
一个关于IO缓冲区的刻骨铭心的经历!
FileInputStream和FileOutputStream类:分别用来创建磁盘文件的输入流 和输出流对象,通过它们的构造方法来指定文件路径和文件名。
创建FileInputStream实例对象时,指定的文件应当是存在和可读的。创建 FileOutputStream实例对像时,如果指定的文件已经存在,这个文件中的原来内容 将被覆盖清楚。
对同一个磁盘文件创建FileInputStream对象的两种方式:
1、FileInputStream inOne=newFileInputStream(“hello.test“);
2、File f = new File(“hello.test”);
FileInputStream inTwo=new FileInputStream(f);
创建FileOutputStream实例对象时,可以指定还不存在的文件名,不能指定一个已被其他程序打开了的文件。
编程举例:用FileOutputStream类向文件中写入一个字符串,然后用FileInputStream读出写入的内容。
import java.io.*;
public class FileStream {
public static void main(String[] args) {
try{
FileOutputStream fos = new FileOutputStream("hello.txt");
fos.write("www.it315.org".getBytes());
fos.close();
byte[] buf = new byte[1024];
File f = new File("hello.txt");
FileInputStream fis = new FileInputStream(f);
int len = fis.read(buf);
System.out.println(new String(buf, 0, len));
fis.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
Reader与Writer类:是所有字符流类的抽象基类,用于简化对字符串输入输出编程,即用于读写文本数据。
二进制文件和文本文件的区别。
编程举例:用FileWriter类向文件中写入一个字符串,然后用FileReader读出写入的内容。
import java.io.*;
public class FileStream2 {
public static void main(String[] args) {
try{
FileWriter fos = new FileWriter("hello2.txt");
fos.write("www.it315.org");
fos.close();
char[] buf = new char[1024];
File f = new File("hello.txt");
FileReader fis = new FileReader(f);
int len = fis.read(buf);
System.out.println(new String(buf, 0, len));
fis.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
PipedInputStream与PipedOutputSream类:用与在应用程序(两个以上的线程)中的创建管道通信。
import java.io.*;
public class Sender extends Thread {
private PipedOutputStream pos = new PipedOutputStream();
public PipedOutputStream getOutputStream(){
return pos;
}
public void run(){
String str = new String("hello,receiver");
try {
pos.write(str.getBytes());
pos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
import java.io.*;
public class Receiver extends Thread{
private PipedInputStream pis = new PipedInputStream();
public PipedInputStream getInputStream(){
return pis;
}
public void run(){
byte [] buf = new byte[1024];
try {
int len = pis.read(buf);
System.out.println("the flowing message comes sender:/n"+new String(buf, 0 ,len));
pis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
import java.io.*;
public class PipedStreamTest {
public static void main(String[] args) {
Sender t1 = new Sender();
Receiver t2 = new Receiver();
PipedOutputStream p1 = t1.getOutputStream();
PipedInputStream p2 = t2.getInputStream();
try {
p1.connect(p2);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t1.start();
t2.start();
}
}
PipedReader和PipedWriter类:与PipedInputStream和PipedOutputSream类似。
使用管道流类,可以实现各个程序模块之间的松耦合通信。具有强类聚弱耦合的特点。
ByteArrayInputStream和ByteArrayOutputStream类:用于以IO流的方式来完成对字节数组内容的读写,来支持类似内存虚拟文件或者内存映像文件的功能。 ByteArrayInputStream的两个构造函数:
ByteArrayInputStream(byte[] buf)
ByteArrayInputStream(byte[] buf,int offset,int lenth)
ByteArrayOutputStream的两个构造函数:
ByteArrayOutputStream()
ByteArrayOutputStream(int)
编程举例:编写一个函数,把输入流中所有的英文字母变成大写字母,然后将结果写入到一个输出流对象。用这个函数来将一个字符串中的所有字符转换成大写。
import java.io.*;
public class ByteArrayTest {
public static void main(String[] args) {
String str = "asfsdgdfhfjghjghkjk";
ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
transform(bis, bos);
byte [] buf = bos.toByteArray();
System.out.println(new String(buf));
}
public static void transform(InputStream in, OutputStream out){
try {
int ch = 0;
while((ch = in.read()) != -1){
int upperCh = Character.toUpperCase((char)ch);
out.write(upperCh);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
StringReader和StringWriter类用来以字符IO流的方式处理字符串。与ByteArrayInputStream和ByteArrayOutputStream类相对应。
重视IO程序代码的复用:System.in连接到键盘,是InputStream类型的实例对象。System.out是连接到显示器,是PrintStream类的实例对象。不管各种底层物理设备用什么方式实现数据的终止点,InputStream的read方法总是返回-1来表示输入刘德结束。在Windows下,按下Ctrl+Z组合键可以产生键盘输入流的结束标记,在Linux下,则是按下Ctrl+D组合键来产生键盘输入流的结束标记。
编程举例:借助上例编写的函数,将键盘上输入的内容转变成大写字母后打印在屏幕上。
import java.io.*;
public class ByteArrayTest {
public static void main(String[] args) {
String str = "asfsdgdfhfjghjghkjk";
ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
transform(bis, bos);
byte [] buf = bos.toByteArray();
System.out.println(new String(buf));
System.out.println(System.in, System.out);
}
public static void transform(InputStream in, OutputStream out){
try {
int ch = 0;
while((ch = in.read()) != -1){
int upperCh = Character.toUpperCase((char)ch);
out.write(upperCh);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
建议:要编程从键盘上连续读取一大段数据时,应尽量将读取数据的过程放在函数中完成,使用-1来作为键盘输入的结束点。在该函数中编写的程序代码不应直接使用System.in读取数据,而是用一个InputStream类型的形式参数对象来读取数据,然后将System.in作为实参传递给InputStream类型的形式参数来调用该函数。
D.字符编码:
计算机里只有数字,计算机软件里的一切都是用数字来表示的,屏幕上显示的 一个个字符也不例外。
ASCII(美国标准信息交换码)。最高bit位都为0,也就是说这写数字豆子0到 127之间。
GB2312(国标码)表示中文字符,用两个字节的数字来表示,中文字符的每 个字节的最高位bit都为1。在GB2312的基础上对更多的中文字符(包括繁体) 进行了编码,新的编码规则称为GBK。在中国大陆使用的计算机系统上,GBK和 GBK2312就被称为系统的本地字符集。
一个字符在不同的本地化系统中出现的字符就不一样,就是我们常见的乱码。
Unicode编码:ISO将全世界所有的符号进行了统一编码,即Unicode编码。
每个字符占两个字节的大小。因此字符个数不会超过2的16次方(65536)。
本地化字符编码与Unicode编码共存。
UTF-8编码:ACSII码字符保持原样,对于其他国家的字符,UTF_8使用两个 或三个字节来表示。使用UTF-8编码的文件,通常都要用EF BB BF做为文件开头 的三个字节数据。
字符的UTF-8的编码与Unicode编码之间的转换关系对应下列规则:
优点:不出现内容为0x00字节;便于应用程序检测数据在传输过程中是否发 生了错误;直接处理使用ASCII的英文文档;
缺点:有的字符需要三个字节。
UTF-16编码的介绍。
E. 各种过滤流和包装类:
缓冲流为I/O流增加了内存缓冲区,增加缓冲区有两个基本目的:
允许Java程序一次不只操作一个字节,这样提高率程序的性能。
由于有了缓冲区,使得在流上执行skip、mark、和reset方法都成为可能。
BufferedInputStream和BufferedOutputStream类:是Java提供的两个缓冲区包装类,不管底层系统是否使用了缓冲区,这两个类在自己的实例对象中创建缓冲。
BufferedInputStream的两个构造函数;
BuffedInputStream(InputStream in)
BufferedInputStream(InputStream in,int size)
BufferedOutputStream的两个构造函数:
BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out,int size)
BufferedReader和BufferedWriter类:BufferedReader的readLine方法可以一次读取一行文本,BufferedWriter的newLine方法可以向字符流中写入不同操作系统下的换行符。
DataInputStream和DataOutputStream类
关闭流栈中的最上层的流对象,将会自动关闭流栈中的所有底层对象。
编程实例:分别使用DataOutputStream类的wrterUTF、wtriterBytes和readChars方法,比较这几个方法的差异。
import java.io.*;
public class AAA {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("Count.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream dos = new DataOutputStream(bos);
dos.writeUTF("ab中国");
dos.writeChars("ab中国");
dos.writeBytes("ab中国");
dos.close();
FileInputStream fis = new FileInputStream("Count.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
System.out.println(dis.readUTF());
byte[] buf = new byte[1024];
int i = dis.read(buf);
//System.out.println(new String(buf,0,i));
}
}
PrintStream类:提供了一系列的print和println方法,可以将基本数据类型的数据格式化成字符串输出。与PrintStream对应的PrintWriter类,即使遇到了文本换行符标识符(/n),PrintWriter类也不会自动清空缓冲区。PrintWriter的println方法能根据操作系统的不同而生成相应的文本换行标识符。在Windows下的文本换行标识符是“/r/n”,而Linux下的文本换行符是“/n”。
ObjectInputStream和ObjectOutputStream类:用于从底层输入流中读取对象类型的数据和将对象数据写入到底层输出流。
它们所读写的对象必须实现了Serializable接口。对象中的transient和static类型的成员变量不会被读取和写入。
编程举例:创建了一个可序列化的学生对象,并用ObjectOutputStream类把它存储到一个文件(mytext.txt)中,然后再用ObjectInputStream类把存储的数据读取到一个学生对象中,即恢复保存的学生对象。
import java.io.Serializable;
public 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;
}
}
import java.io.*;
public class Serialization {
public static void main(String[] args) {
// TODO Auto-generated method stub
Student stu1 = new Student(19,"zhangsan",25,"huaxue");
Student stu2 = new Student(20,"lisi",23,"wuli");
try {
FileOutputStream fos = new FileOutputStream("student.txt");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(stu1);
os.writeObject(stu2);
os.close();
FileInputStream fis = new FileInputStream("student.txt");
ObjectInputStream is = new ObjectInputStream(fis);
stu1 = (Student)is.readObject();
stu2 = (Student)is.readObject();
is.close();
System.out.println("id:"+stu1.id);
System.out.println("name:"+stu1.name);
System.out.println("age:"+stu1.age);
System.out.println("department:"+stu1.department);
System.out.println();
System.out.println("id:"+stu2.id);
System.out.println("name:"+stu2.name);
System.out.println("age:"+stu2.age);
System.out.println("department:"+stu2.department);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
一个可以被序列化的MyClass类的定义:
Public class MyClass implements Serializable{
Public transient Thread t;
Private String custormerID;
Private int total;
}
F. 字节流与字符流的转换
InputStreamReader和OutputStreamWriter,是用于将字节流转换成字符流来读写的两个类,InputStreamReader可以将一个字节流中的字节解码成字符后读取,OutputStreamWriter将字符编码成自节后写入到一个字节流中。
InputStreamReader的两个主要的构造函数:
InputStreamReader(InputStream in);
InputStreamReader(InputStream in,StringCharsetName);
OutputStreamWriterr的两个主要的构造函数:
OutputStreamWriterrr(OutputStream out);
OutputStreamWriterr(OutputStream out,StringCharsetName);
最好不要直接使用InputStreamReader和OutputStreamWriter类读写数据,应尽量使用BufferedWriter类包装OutputStreamWriter类,用BufferedReader类包装InputStreamReader。这样可以避免频繁地在字符和字节之间进行转换。.
G.Java程序与其他进程的数据通信
在Java程序中可以用Proces类的实例对象来表示子进程,子进程的标准输入和输出不再连接到键盘和显示器,而是以管道流的形式连接到父进程的一个输出流和输入流对象上。
调用Proces类的getOutputStream和getInputStream方法可以获得连接到子进程的输出流和输入流对象。
提高程序的运行效率:
(1)for(int i=0;i<str.length();i++){
…..
}
与下面代码的比较:
int len = str.length();
for(int i=o;i<len;i++){
……
}
(2) byte[] buf=new byte[1024];
while(true){
对buf元素的操作语句
}
与下面代码的比较:
while(true){
byte[] buf= new byte[1024];
对buf元素的操作语句
}
H. Decrator设计模式:在程序中用一个对象(the Decorators)包装另外的一个对象,只是一种被称为Decrator的设计模式。