File类
①IO包中唯一代表磁盘文件本身信息的类,而不是文件中内容。
②定义了一些与平台无关的方法来操纵文件,例如:创建,删除文件各重合文件。
java中的目录被当作一种特殊的文件使用,list方法可以返回目录中的所有子目录和文件名。
在Unix下的路征分隔符为(/),在Dos下的路征分隔符为(/),java可以正确处理Unix和Dos的路征分隔符。
import java.io.File;
import java.io.IOException;
import java.util.Date;
public class FileTest {
public static void main(String[] args) {
File f = new File("1.txt");
if(f.exists()){ //文件是否存在
f.delete(); 删除文件
}else{
try {
f.createNewFile();
} catch (IOException e) {
e.printStackTrace(); //创建文件
}
}
System.out.println("获取文件名:"+f.getName());
System.out.println("获取文件的路径:"+f.getPath());
System.out.println("获取文件的绝对路径:"+f.getAbsolutePath());
System.out.println("获取文件的父目录:"+f.getParent());
System.out.println(f.exists() ? "exists" : "not exists");
System.out.println("文件是否可读:"+(f.canRead() ? "read" : "not read"));
System.out.println("文件是否可写"+(f.canWrite() ? "write" : "not write"));
System.out.println("文件是否是目录:"+(f.isDirectory() ? "directory" : "not directory"));
System.out.println("获取文件的最后一次被修改的时间:"+new Date(f.lastModified()).toString());//f.lastModified(),为long型
}
}
RandomAccessFile类
它提供众多文件访问方法,支持“随机访问”方式
随机读写等长记录格式的文件时有很大的优势,仅限于操作文件,不能访问其它的IO设备,如网络,内存映像等。
两种构造方法:
new RandomAccessFile(f,"rw"); //读写方式
new RandomAccessFile(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",24);
Employee e3 = new Employee("Wangwu",25);
RandomAccessFile ra=new RandomAccessFile("c://employee.txt","rw");
ra.writeChars(e1.name.getBytes());//getBytes转换为字节数组
ra.writeInt(e1.age);//writeInt,将四个字节数据都写到文件之中
ra.writeChars(e2.name.getBytes());
ra.writeInt(e2.age);
ra.writeChars(e3.name.getBytes());
ra.writeInt(e3.age);
ra.close();
int len=0;
String strName = "";
byte [] buf = new byte[Employee.LEN]
RandomAccessFile raf=new RandomAccessFile("c://1.txt","r");
raf.skipBytes(Employee.LEN + 4); //跳过第一个员工的信息,其中姓名8字节,年龄4字节
//len=raf.read(buf);
//strName = new String(buf,0,len);
for(int i;i<Enployee.LEN;i++)
{
strName += raf.readChar();
}
System.out.println(strName.trim()+":"+raf.readInt());
//第一个员工
raf.seek(0);
//len = raf.rend(buf);
//strName = new String(buf,0,len);
for(int i;i<Enployee.LEN;i++)
{
strName += raf.readChar();
}
System.out.println(strName.trim()+":"+raf.readInt());//strName.trim()去掉不可见字符
//第三个员工
raf.seek(Employee.LEN);
len = raf.rend(buf);
strName = new String(buf,0,len);
System.out.println(strName+":"+raf.readInt());
/*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
{
public String name = null;
public int age;
public final static int LEN=8;
public Employee(String name,int age)
{
if(name.length()>LEN)
{
name = name.substring(0,LEN);//取出第0到LEN-1之间的字符
}
else
{
while(name.length()<LEN)
name=name+"/u0000";//填充空字符
}
this.name=name;
this.age=age;
}
}
节点流
流是字节序列的抽象概念
文件是数据的静态存储形式,而流是指数据传输时的形态
流类分为两个大类:节点流类和过滤流类(也叫处理流类)
InputStream类
程序可以从中连续读取字节的对象叫输入流,在java中,用InputStream类来描述所有输入法流的抽象概念
int read() //从输入流中读取数据的下一个字节
int read(byte[] b) //从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中
int read(byte[] b, int off, int len) //将输入流中最多 len 个数据字节读入 byte 数组
skip(long n) //跳过和丢弃此输入流中数据的 n 个字节 (包装类)
available() //返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数
mark(int readlimit) //在此输入流中标记当前的位置
markSupported() //测试此输入流是否支持 mark 和 reset 方法
reset() //将此流重新定位到最后一次对此输入流调用 mark 方法时的位置
close() //关闭此输入流并释放与该流关联的所有系统资源
OutputStream类
程序可以向其中其中写入字节的对象叫输出流,在java中,用OutPutStream类来描述所有输出流的抽象概念
write(byte[] b) //将 b.length 个字节从指定的 byte 数组写入此输出流
write(int b) //将指定的字节写入此输出流
write(byte[] b, int off, int len) //将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流
flush() //刷新此输出流并强制写出所有缓冲的输出字节
close() //关闭此输出流并释放与此流有关的所有系统资源
FileInputStream与FileOutputStream
FileInputStream和FileOutputStream类分别用来创建磁盘文件的输入和输出流对象,通过它们的构造函数来指定文件路征和文件名
创建FileInputStream实例对象时,指定的文件应当是存在和可读的。创建FileOutStream实例对象时,如果指定文件已经存在,这个文件的原内容将被覆盖清除。
对同一个磁盘文件创建FileInputStream对象的两种方式:
(1)FileInputStream inOne = new FileInputStream("hello.txt");
(2)File f = new File("hello.txt");
FileInputStream inTwo = new FileInputStream(f);
创建FileOutputStrem实例对象时,可以指定还不存在的文件名,不能指定一个已被其它程序打开了的文件。
编程实例:
package cn.com.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileStream {
public static void main(String[] args) {
try {
FileOutputStream out = new FileOutputStream("hello.txt");
out.write("hello world".getBytes());
out.close();
byte[] buf = new byte[1024];
File f = new File("hello.txt");
FileInputStream in = new FileInputStream(f);
int len = in.read(buf);
in.close();
System.out.println(new String(buf,0,len));
} catch (Exception e) {
e.printStackTrace();
}
}
}
Reader与Writer(字符)
Reader和Writer 是所有字符流的抽象基类,用于简化对字符串的输入输出编程,即用于读写文本数据
FileWriter用于写入字符流 FileOutputStream 要写入原始字节流
实例:
package cn.com.io;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileStream2 {
public static void main(String[] args) {
try {
FileWriter out = new FileWriter("hello.txt");
out.write("hello world2");
out.flush();
out.close();
char[] buf = new char[1024];
FileReader in = new FileReader("hello.txt");
int len = in.read(buf);
System.out.println(new String(buf,0,len));
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
PipedInputStream与PipedOutStram类
PipedInputStream和PipedOutputStream 以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端,输入流是管道的接收端。
PipedWriter和PipedReader类。(字符管道通信)
使用管道流类,可以实现各个程序模块之间的松耦合通信。
ByteArrayInputStream与ByteArrayOutputStream类
ByteArrayInputStream和ByteArrayOutputStream此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据
用于以IO流的方式来完成对字节数组内容的读写,来支持类似内存虚拟文件或者内存映像文件的功能。
System.in连接键盘,是InputStream类型的实例对象
System.out 连接显示器,是PrintStream类的实例对象。
不管各种底层物理设备用什么方式实现数据的终止点,InputStream的read方法总是返回-1来表示输入流的结束。
在Windows下,按下Ctrl+Z组合可以产生键盘输入流的结束标记,在liunx下,则是按下Ctrl+D组合键来产生键盘输入流的结束标记。
建议:要编程从键盘上连续读取一大段数据时,应尽量将读取数据的过程放在函数中完成,使用-1来作为键盘输入的结束点。在该函数中编写的程序代码不应直接使用System.in读取数据,而是用一个InputStream类型的形式
参数对象来读取数据,然后将System.in作为实参传递给InputStream类型的形式参数来调用该函数。
字符编码
a对应数字是97,字符与数字对应的编码规则被称为ASCII(美国标准信息交换码)。ASCII的最高位是0,也就是说这些数字都在0到127之间。
中国大陆将每一个中文字符都用两个字节的数字表示,中文字符的每个字节的最高位bit都为1,中国大陆为每个中文字符制定的编码规则称为GB2312(国标码)。
在GB2312的基础上,对更多的中文字符(包括繁体)进行了编码,新的编码规则称为GBK。
在中国大陆使用的计算系统上,GBK和GB2312就被称为该系统的本地字符集。
台湾地区对中文字符集的编码规则称为BIG5(大五码)。
Unicode编码
Unicode编码的字符都占用两个字节的大小,对于ASCII码所表示的字符,只是简单地在ASCII码原来占用的一个字节前面,增加一个所有bits为0的字节。
Unicode只占用两个字节,在全世界范围内所表示的字符个数不会超过2的16次方(655536),实际上,Unicode编码中还保留了两千多个数值没有用于字符编码。
java中的字符使用的Unicode编码,java在通过Unicode保证跨平台特性的前提下,也支持本地平台字符集。
UTF-8编码
ASCII码符保持原样,仍然只占用一个字节,对于其它国家的字符,UTF-8使用两个或三个字节来表示。使用UTF-8编码的文件,通常都要用EE BB BF作为文件开头的三个字节数据。
UTF-8优点
不出现内容为0x00字节
便于应用程序检测数据在传输过程中是否发生了错误
直接处理使用ASCII码的英文文档
UTF-8的缺点
在某些特殊的文字需要三个字节(如中日韩)
UTF-16编码
UTF-16编码在Unicode基础上进行了一些细节上的扩充,增加了对Unicode编码没有包括的那些字符的表达式。
UTF-16对Unicode的扩充并没有影响Unicode编码所包括的哪些字符,只是增加了对Unicode编码没有包括的那些字符的表达方式,一个使用Unicode编码的字符就是UTF-16格式的。
Unicode编码将0XD800-0XDFFF区间的数值保留出来,UTF-16扩充的字符,占用4个字节,前面两个字节的数值为0XD8000-0XD8FF之间,后面两个字节的数值为0XDC00-0XDFFF之间。
为什么不让前面后面的两个字节的数值都位于0XD800-0XDFFF之间呢?
0XDC00-0XDFFF已经足够满足全世界各国文字;前后数值都位于0XD800-0XDFFF不便于区分两个字节。
在不同体系结构的计算机系统中,UTF-16编码的Unicode字符在内存中的字节存储顺序是不同的。
如果文件以0XFE 0XFF这两个字节开头,则表明文本的其余部分是Big-Endian的UTF-16编码;如果
文件以0XFF 0XFE这两个字节开头,则表明文本的其余部分是Little-Endian的UTF-16编码。
编程实例:
package cn.com.io;
import java.io.UnsupportedEncodingException;
public class Charcode {
public static void main(String[] args) {
System.setProperty("sun.jnu.encoding", "iso8859-1"); //按指定字符编码设置属性文件
System.getProperties().list(System.out); //获取属性文件
String strChina = "中国";
for(int i=0;i<strChina.length();i++){ //toHexString(int i) :十六进制返回一个整数参数的字符串
System.out.println(Integer.toHexString((int)strChina.charAt(i)));
}
try {
byte[] buf = strChina.getBytes("gb2312");
for(int str : buf){
System.out.println(Integer.toHexString(str));
}
for(int i=0;i<buf.length;i++){
System.out.write(buf[i]); //输出流形式输出
}
System.out.println(); //刷新缓冲区
System.out.write(buf,0,4); //自动刷新缓冲区
System.out.println("/n中国"); //PrintStream.println(String str)
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
package cn.com.io;
import java.io.IOException;
public class CharDecode {
public static void main(String[] args) {
System.getProperties().put("file encoding", "iso8859-1");
System.out.println("please enter a chinese String:");
byte[] buf = new byte[1024];
int pos = 0;
String strInfo;
int ch;
while(true){
try {
ch = System.in.read();
System.out.println(Integer.toHexString(ch));
switch(ch){
case '/r':
break;
case '/n':
strInfo = new String(buf,0,pos,"gb2312");
for(int i=0;i<strInfo.length();i++){
System.out.println(Integer.toHexString(strInfo.charAt(i)));
}
System.out.println(new String(strInfo.getBytes("iso8859-1"),"gb2312"));
pos = 0;
break;
default:
buf[pos++] = (byte) ch;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
包装类的概念与作用
通过完成某个特殊功能的类,称为包装类或者称为过滤流类
DateOutputStream并没有对应到任何具体的流设备,一定要给它传递一个对应具体流设备的输出流对象,完成类似DateOutputStream功能的类就是一个包装类,也叫过滤流类或处理流类。
DateOutputStream包装类的构造函数语法:
public DateOutputStream(OutputStream out)
DateOutputStream的部分方法列表;
程序-->方法A、B、C->方法1--》目标
包装流类 节点流类
BufferedInputStream与BufferedOutputStream类
缓冲流为I/O流增加了内存缓冲区,增加缓冲区有两个基本的:
①允许java程序一次不只操作一个字节,这样提高了程序的性能。
②由于有了缓冲区,使得在流上执行skip、mark和reset方法都成为可能。
BufferedInputStream和BufferedOutputStream是java提供的两个缓冲区包装类,不管底层系统是否使用了缓冲区,这两个类在自己的实例对象中创建缓冲区。
BufferedInputStreamr的两个构造函数:
BufferedInputStream(InputStream in)//带有32个字节的缓冲区
BufferedInputStream(InputStream in,int size)//自定义缓冲区大小
BufferedOutputStream的两个构造函数:
BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out,int size)
BufferedReader的readLine方法可以一次读取一行文本,BufferedWriter的newLine方法可以向字符流中写人不同操作系统下的换行符。
DataInputStream与DataOutStream类
DataOutputStream类提供了三个写入字符的方法:
public final void writeBytes(String s)
public final void writeChars(String s)
public final void writeUTF(String s)
DataInputStream类中有一个readUTF方法,并没有“readBytes”和“readChars”方法。
关闭流栈中的最上层的流对象,将会自动关闭流栈中的所有底层流对象。
编程实例:分别使用DataOutputStream类的writeUTF、writeBytes和writeChars方法,比较这几个方法的差异。
package cn.com.io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class DataStreamTest {
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("count.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream dos = new DataOutputStream(bos);
dos.writeUTF("China 中国");
dos.writeBytes("China 中国");
dos.writeChars("China 中国");
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 len = dis.read(buf);
System.out.println(new String(buf,0,len));
dis.close();
}
}
PrintStream类
PrintStream类提供了一系列的print和println方法,可以将基本数据类型的数据格式化成字符串输出。
格式化输出:例如,97被格式化输出的实际字节数据为0X39和0X37。
PrintStream的3个构造函数:
PrintStream(OutputStrean out)
PrintStream(OutputStream out,boolean outoflush)
PrintStream(OutputStream out,noolean outoflush,String encoding)
与PrintStream对应的PrintWriter类,即使遇到了文本换行符(/n),PrintWriter类也不会自动清空缓冲区。
PrintWrite的println方法能根据操作系统的不同而生成相应的文本换行标识符。在Windows下的文本换行标识符是“/r/n”,而Linux下的文本换行标识符是"/n";
ObjectInputStream与ObjectOutputStream类
ObjectInputStream和ObjectOutputStream这两个包装类,用于从底层输入流中读取对象类型的数据和将对象类型的数据写入到底层输出流。
ObjectInputStream与ObjectOutputStream类所读写的对象必须实现了Serializable接口。对象中的transient(临时变量)和static类型的成员变量不会被读取和写入。
一个可以被序列化的MyClass类的定义:
public class MyClass implements Serializable{
public transient Thread t;
private String CustomerID;
private int total;
}
字节流与字符流的转换
BufferedReader in = new BufferedReader(new InputStreamReader(System.in))读取键盘上输入的一行字符。
InputStreamReader和OutputStreamWriter,是用于将字节流转换成字符流来读写的两个类,InputStreamReader可以将一个字节流中的字节解码成字符后读取,OutputStreamWriter将字符编码成字节后写入到一个字节流中。
InputStreanReader的两个主要的构造函数:
InputStreamRead(InputStream in)
InputStreamRead(InputStream in,String CharsetName);
OutputStreanWriter的两个主要的构造函数:
OutputStreamWriter(OutputStream out)
OutputStreamWriter(OutputStream out,String CharsetName);
避免频繁地在字符与字节间进行转换,最好不要直接使用InputStreamRead和OutputStreamWriter类来读写数据,应尽量使用BufferedWrite类包装OutputStreamWriter类,用于BufferderReader类包装InputStreamrader.
java程序与其它进程的数据通信
在java程序可以用Process类的实例对象来表示子进程,子进程的标准输入和输出不再连接到键盘和显示器,而是以管道流的形式连接到父进程的一个输出流和输入流对象上。
调用Process类的getOutputStream和getInputStream方法可以获得连接到子进程的输出流和输入流对象。
编程实例:在TestInOut类中启动java.exe命令执行另外一个MyTest类,TestInOut和MyTest通过进程间的管道相互传递数据。调用Process类的destroy方法结束子进程的运行。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class MyTest {
public static void main(String[] args) throws IOException {
BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
while(true){
String strLine = bfr.readLine();
if(strLine != null){
System.out.println("hi:" +strLine);
}else{
return;
}
}
}
}import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
public class TestInOut implements Runnable{
Process p = null;
public TestInOut() {
try {
p =Runtime.getRuntime().exec("java MyTest");//外部命令
new Thread(this).start(); //this当前对象
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
TestInOut tio = new TestInOut();
tio.send();
}
public void send(){
OutputStream ops = p.getOutputStream();
try {
while(true){
ops.write("help/r/n".getBytes());
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
InputStream in = p.getInputStream();
BufferedReader bfr = new BufferedReader(new InputStreamReader(in));
String strLine;
try {
while(true){
strLine = bfr.readLine();
if(strLine != null){
System.out.println(strLine);
}else{
return;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Decorator设计模式
在程序中用一个对象(the Decorators)1包装另外的一个对象,这是一种被称为Decorator的设计模式。
如果要设计自己的IO包装类,这个类需要继承以FilterXXX命名的类,设计一个对输入输出包装类:
RecordInputStream和RecordOutputStram,来完成从数据库文件中读取记录和往数据库文件中写入记录。
Exception类从Throwable类继承的三个PrintStackTrace方法的定义如下:
public void printStackTrace();
public void printStackTrace(PrintStream s)
public void printStackTrace(PrintWriter s)
编程实例:把printStackTrace方法打出的详细异常信息储存到字符串中
package cn.com.io;
import java.io.PrintWriter;
import java.io.StringWriter;
public class TestPrintWriter {
public static void main(String[] args) {
try{
throw new Exception("test");
}catch(Exception e){
StringWriter sw = new StringWriter();
PrintWriter pw =new PrintWriter(sw);
e.printStackTrace(pw);
System.out.println(e.getMessage());
System.out.println(sw.toString());
}
}
}