Java之IO流

                                         Java之IO流

1 IO流

Java中I/O操作主要是指使用Java进行输入,输出操作,即设备之间的数据传输。

1.1 File类

File类是java.io包下的,对文件和目录操作,包括文件的创建,删除,修改等操作。但 File 不能访问文件内容本身,如果需要访问文件内容本身,则需要使用输入/输出流。

想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录。 File对象可以作为参数传递给流的构造器 。

File 类常用构造器如下:

构造器描述
public File(String pathname)以pathname为路径创建File对象,可以是绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。
public File(String parent,String child)以parent为父路径,child为子路径创建File对象。
public File(File parent,String child)根据一个父File对象和子文件路径创建File对象

常用API如下:

方法描述
String getName()返回文件名或目录名
String getPath()返回路径名字符串
File getAbsoluteFile()返回绝对路径名的File对象
String getAbsolutepath()返回绝对路径名的字符串
String getParent()返回上一次路径名字符串
boolean renameTo(File newName)重命名次路径表示的文件(调用的对象必须要存在,并且在同一磁盘下)
boolean exists()

                    判断文件或目录 是否存在

boolean canWrite()

                               是否可写

boolean canRead()

                               是否可读

boolean isFile()

                            是否是一个文件

boolean isDirectory()

                             是否是一个目录

long lastModified()

                            最后的修改时间

long length()

                              文件的大小

boolean createNewFile()创建新文件
boolean delete()删除文件
boolean mkDir()

             创建目录,上级目录 必须存在

boolean mkDirs()

             创建目录,上级目录 可以不存在

String[] list()

         遍历当前目录下的文件返回文件的名称

File[] listFiles()

         遍历当前目录 下的文件返回的文件对象

注意:路径分隔符和系统有关,windows和DOS系统默认使用“\”来表示,UNIX和URL使用“/”来表示。为了解决这个隐患,File类提供了一个常量:public static final String separator。根据操作系统,动态的提供分隔符。 如:File file = new File("d:" + File.separator + "study" + File.separator + "hello.txt");

1.2 IO流原理

I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。 所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列。IO又分为流IO(java.io)和块IO(java.nio)。

注意:磁盘到内存(是输入操作input),内存到磁盘(是输出操作output)。

1.3 IO流分类

(1)按操作数据单位分:字节流8bit(一般操作非文本文件),1byte = 8bit,字符流16bit(一般操作文本文件),1char = 2byte = 16bit;

(2)按流向分:输入流(磁盘到内存),输出流(内存到磁盘);

(3)按角色不同分:节点流(4),处理流(N)。

节点流:直接从数据源或目的地读写数据。处理流:不能直接连接到数据源或目的地,而是连接已经存在的流(可以是节点流或处理流)之上,通过对数据的处理为程度提供更强大的读写能力。

常用的几个IO流如下

抽象父类节点类缓冲流
InputStream(二进制格式操作)FileInputStreamBufferedInputStream
OutputStream(二进制格式操作)FileOutputStreamBufferedOutputStream
Reader(文件格式操作)FileReaderBufferedReader
Writer(文件格式操作)FileWriterBufferedWriter

1.4 节点流

节点流:可以从或向一个特定的地方(节点)读写数据。

(1)FileInputStream与OutputStream。

InputStream常用方法

int read()从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1
int read(byte[] b)从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。否则以整数形式返回实际读取的字节数。
int read(byte[] b, int off,int len)将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节,但读取的字节也可能小于该值。以整数形式返回实际读取的字节数。如果因为流位于文件末尾而没有可用的字节,则返回值 -1
close()关闭此输入流并释放与该流关联的所有系统资源。

OutputStream常用方法

void write(int c)将指定的字节写入此输出流。write 的常规协定是:向输出流写入一个字节。要写入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。即写入0~255范围的。
void write(byte[] b)将b.length 个字节从指定的 byte 数组写入此输出流。write(b) 的常规协定是:应该与调用 write(b, 0, b.length) 的效果完全相同。
void write(byte[] b,int off,int len)将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
void flush()刷新此输出流并强制写出所有缓冲的输出字节,调用此方法指示应将这些字节立即写入它们预期的目标。
close()关闭此输出流并释放与该流关联的所有系统资源。
//文件的复制
	@Test
	public void copy() {
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try {
			//创建输入流
			fis = new FileInputStream(new File("jdbc.properties"));
			//创建输出流
			fos = new FileOutputStream("copy.txt");
			//创建字节数组
			byte[] buffer = new byte[1024];
			int len;
			while((len = fis.read(buffer))!=-1) {
				fos.write(buffer, 0, len);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(fos!=null) {
					
				}
				if(fis!=null) {
					fis.close();
				}			
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
		
	}

(2)FileReader和FileWriter是先文件的复制

Reader常用方法

int read()读取单个字符。作为整数读取的字符,范围在 0 到 65535 之间 (0x00-0xffff)(2个字节的Unicode码),如果已到达流的末尾,则返回 -1
int read(char[] cbuf)将字符读入数组。如果已到达流的末尾,则返回 -1。否则返回本次读取的字符数。
int read(char[] cbuf,int off,int len)将字符读入数组的某一部分。存到数组cbuf中,从off处开始存储,最多读len个字符。如果已到达流的末尾,则返回 -1。否则返回本次读取的字符数。
close()关闭此输入流并释放与该流关联的所有系统资源。

Writer 常用方法

void write(int c)写入单个字符。要写入的字符包含在给定整数值的 16 个低位中,16 高位被忽略。 即 写入0 到 65535 之间的Unicode码。
void write(char[] cbuf)写入字符数组。
void write(char[] cbuf,int off,int len)写入字符数组的某一部分。从off开始,写入len个字符
void write(String str)写入字符串。
void write(String str,int off,int len)写入字符串的某一部分。
void flush()刷新该流的缓冲,则立即将它们写入预期目标。
close()关闭此输出流并释放与该流关联的所有系统资源。
@Test
	public void copy2() {
		FileReader fr = null;
		FileWriter fw = null;
		try {
			//创建输入流
			fr = new FileReader(new File("jdbc.properties"));
			//创建输出流
			fw = new FileWriter("copy.txt");
			//创建字符数组
			char[] buffer = new char[1024];
			int len;
			while((len = fr.read(buffer))!=-1) {
				fw.write(buffer, 0, len);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(fw!=null) {	
					fw.close();
				}
				if(fr!=null) {
					fr.close();
				}			
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
		
	}

 

1.5 缓冲流

缓冲流是处理流的一种,建立在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了效率,还增加了一些新的方法。BufferedReader新增了readline()用于此意读取一行字符串,以\r或\n认为一行结束,BufferedWriter新增了newLine()用于写出一个行分隔符。

注意:①对于缓冲输出流,写出的数据会先缓存在内存缓冲区中,关闭流前要用flush()将缓冲区的数据立刻写出。②关闭流的顺序和打开流的顺序相反。只要关闭最外层流即可,关闭最外层流也会相应关闭内层节点流③如果是带缓冲区的流对象的close()方法,不但会关闭流,还会在关闭流之前刷新缓冲区,关闭后不能再写出

//缓冲流操作字节
	@Test
	public void copy3() {
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		try {
			bis = new BufferedInputStream(new FileInputStream(new File("copy.txt")));
			bos = new BufferedOutputStream(new FileOutputStream(new File("copy.txt2")));
			byte[] buffer = new byte[1024];
			int len;
			while((len=bis.read(buffer))!=-1) {
				bos.write(buffer,0,len);
				//刷新缓冲
				bos.flush();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(bos!=null) {	
					bos.close();
				}
				if(bis!=null) {
					bis.close();
				}			
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
				
	}
	//缓冲流操作字符
	@Test
	public void copy4() {
		BufferedReader br = null;
		BufferedWriter bw = null;
		try {
			br = new BufferedReader(new FileReader(new File("copy.txt")));
			bw = new BufferedWriter(new FileWriter(new File("copy.txt1")));
			String len;
			while((len=br.readLine())!=null) {
				bw.write(len);
				//换行
				bw.newLine();
				//刷新缓冲
				bw.flush();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(bw!=null) {	
					bw.close();
				}
				if(br!=null) {
					br.close();
				}			
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}

1.6 转换流

InputStreamReader:将字节输入流转换为字符输入流(字节流转向字符流),可以读取不同编码格式的文件 需要使用到 FileInputStream类。

OutputStreamWriter:将字符输出流转换为字节输出流(字符流转向字节流),字符流转向字节流 可以使用不同编码格式写入 需要使用到FileOutStream类。

使用标准输入输出流实现Scanner,标准的输入流:System.in,标准的输出流:System.out。

很多时候使用转换流来处理文件乱码问题,实现编码和解码的功能。

public class TestMyScanner {
	public static void main(String[] args) {
		//接收键盘输入字符信息,并且打印
		System.out.println("请输入信息");
		MyScanner mc = new MyScanner(System.in);
		System.out.println(mc.nextString());	
	}
	
}
class MyScanner {
	InputStream is;
	public MyScanner(InputStream is) {
		this.is= is;
	}
	//接收输入字符串
	public String nextString() {
		//将输入的字节流装换成字符流
		InputStreamReader isr = new InputStreamReader(is);
		//将字符流装换成缓冲流
		BufferedReader br = new BufferedReader(isr);
		String len =null;
		try {
			len = br.readLine();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return len;
	}
	//接收int
	public int nextInt() {
		int result = Integer.parseInt(nextString());
		return result;
	}
}

1.7 对象流

对象流的主要作用就是将Java对象序列化(持久化),并保存到本地磁盘文件,或者将磁盘文件反序列化成Java对象。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。

对象流:ObjectInputStrem和ObjectOutputStrem

序列化:对象信息存储到文件中这个过程叫序列化;

反序列化:从文件中将信息返回给对象的过程叫反序列化。

注意:(1)所保存的对象必须实现Serializable接口,所保存的对象的属性也必须实现Serializable接口;

(2)最好要给该对象提供一个版本号,private static final long serialVersionId;

(3)Static , transient修饰的属性不能序列化的。

public class TestObjectIO {
    //序列化操作
    @Test
    public void serialization() throws FileNotFoundException, IOException {
        Person2 p = new Person2("小明",18,new Account(100.0));
        Person2 p1 = new Person2("小红",18,new Account(200.0));
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("E:\\test\\object.obj")));
        oos.writeObject(p);
        oos.writeObject(p1);
    }
    //反序列化操作
    @Test
    public void deserialization() throws FileNotFoundException, IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("E:\\test\\object.obj")));
        Person2 p = (Person2) ois.readObject();
        System.out.println(p);
        Person2 p1 = (Person2) ois.readObject();
        System.out.println(p1);
    }
}
class Person2 implements Serializable{
    private static final long serialVersionUID = -4043673773479922618L;
    
    private String name;
    private Integer age;
    private Account ac;
    public Person2(String name, Integer age, Account ac) {
        super();
        this.name = name;
        this.age = age;
        this.ac = ac;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", ac=" + ac + "]";
    }
    
}
class Account implements Serializable {    
    
    private static final long serialVersionUID = -4043673773479922617L;
    private double balance;

    public Account(double balance) {
        super();
        this.balance = balance;
    }

    @Override
    public String toString() {
        return "Account [balance=" + balance + "]";
    }
    
}

1.8 数据操作流

java中提供了两个与平台无关的数据操作流:(1)DataInputStream(继承自FillterInputStream类,同时实现DataOutput接口):数据输入流(2)DataOutputStream(继承自FillterOutputStream类,同时实现DataOutput接口):数据输出流。数据操作流通常按照一定格式将数据输出,再按照一定格式将数据输入。

注意:DataOutput接口和DataInput接口。两个数据操作流的方法都是继承两个接口的方法,这两个接口的操作,彼此对应,而且以后还要使用。

DataInputStream:boolean readBoolean() ,byte readByte(),char readChar() ,float readFloat(),double readDouble() ,short readShort(),long readLong() ,int readInt(),String readUTF() 读字符串  ,void readFully(byte[] b)  读字节数组 。

public class TestDataIO {
	@Test
	public void dataOutputStream() throws Exception {
		DataOutputStream dos = new DataOutputStream(new FileOutputStream(new File("E:\\test\\a.txt")));
		try {
			dos.writeUTF("中国");
			dos.writeInt(5);
			dos.writeChar('a');
			dos.writeBoolean(true);
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}
	@Test
	public void dataInputStream() throws FileNotFoundException {
		DataInputStream dis = new DataInputStream(new FileInputStream(new File("E:\\test\\a.txt")));
		try {
			System.out.println(dis.readUTF());
			System.out.println(dis.readInt());
			System.out.println(dis.readChar());
			System.out.println(dis.readBoolean());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

1.9 打印流

在整个IO包中,打印流是输出信息最方便的类,打印流提供了非常方便的打印功能,主要包含字节打印流PrintStream和字符打印流PrintWriter,可以打印任何类型的数据。

常用构造方法PrintStream(File file),PrintStream(OutputStream out)等,PrintStream常用方法如下:

方法描述
PrintStream printf(Locale l, String format, Object... args)  根据指定的locale进行格式化输出
PrintStream printf(String format, Object... args) 根据本地环境格式化输出
void print(Object obj)输出任意类型
void println(Object obj)  输出任意类型后换行

使用打印流有时会比较方便,比如不用像OutputStream那样输出字符串的时候还需要将String转成字节数组再输出。创建打印流的时候通过直接接收OutputStream的构造方法,将OutputStream重新包装了一下,使得输出更加方便。

格式化输出的需要指出其数据类型,如下表。

字符描述
%s表示内容为字符串
%d表示内容为整型
%f表示内容为小数
%c表示内容为字符
public class TestPrintStream {
	public static void main(String[] args) {
		PrintStream ps =null;
		try {
			ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File("printStream.txt"))));
			ps.println("打印流");
			ps.println(66.666);
			String name = "refuel";
			int age = 18;
			double income = 100000.0;
			char gender = 'M';
			ps.printf("姓名:%s;年龄:%d;收入:%f;性别:%c",name,age,income,gender);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}finally {
			if(ps!=null) {
				ps.close();
			}
			
		}
		
	}
}
/*
 *      打印流
 *	66.666
 *	6姓名:refuel;年龄:18;收入:100000.000000;性别:M
 */

总结:PrintStream 可以方便的完成输出的功能,所以输出都可以用它,PrintStream 属于装饰设计模式。

 

1.10 随机输入输出流

随机输入输出流RandomAccessFile:(1)该类可以作为输入,也可以输出,可以实现修改内容(替换、插入)。(2)与普通的输入输出流不一样的是RamdomAccessFile可以任意的访问文件的任何地方。

RandomAccessFile的对象包含一个记录指针,用于标识当前流的读写位置,这个位置可以向前移动,也可以向后移动。有两个方法操作这个指针:(1)long getFilePoint():记录文件指针的当前位置。(2)void seek(long pos):将文件记录指针定位到pos位置。

RandomAccessFile操作文件的4种模式的mode的值代表读写方式,如下:

描述
r以只读方式打开文件,如果写入会报IO异常
ws以读写方式打开指定文件,不存在就创建新文件
rws除了‘rw‘功能以外,文件内容或者元数据更新时一同写入
rwd除了‘rw‘功能以外,文件内容更新时一同写入
public class TestRandomAccess {
	//abcxydef  插入
	@Test
	public void test3() throws Exception {
		RandomAccessFile raf = new RandomAccessFile(new File("RandomAccess.txt"), "rw");
		raf.seek(3);  //将光标移3位置
		String str=raf.readLine();  //光标放最后  def 
		raf.seek(3);
		raf.write("xy".getBytes());   //替换abcxy  f
		raf.write(str.getBytes());   //abcxydef
		raf.close();
	}
	//abcdef    替换
	@Test
	public void test2() throws Exception {
		RandomAccessFile raf = new RandomAccessFile(new File("RandomAccess.txt"), "rw");
		raf.seek(3);  //将光标移3位置
		raf.write("xy".getBytes());   //替换  abcxyf
		raf.close();
	}
	//通过随机访问流实现文件的复制
	@Test
	public void test1() throws Exception {
		
		RandomAccessFile raf1 = new RandomAccessFile(new File("RandomAccess1.txt"), "r");
		RandomAccessFile raf2 = new RandomAccessFile(new File("RandomAccess2.txt"), "rw");
		
		byte[] b =new byte[5];
		int len;
		while((len=raf1.read(b))!=-1) {
			raf2.write(b, 0, len);
		}
		raf2.close();
		raf1.close();
	}
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值