黑马程序员_java IO技术学习总结

时间:2023-02-18 07:29:07

  -------<a href="http://www.itheima.com/"">android培训</a>、<a   href="http://www.itheima.com/" ">java培训</a>期待与您交流!----------

 

                                                         黑马程序员_ javase IO技术学习总结

 

java IO 技术是用来解决设备与设备之间数据交换的问题。IO 是Input Output Stream的简称。

IO流从类型分为:字节流InputStream OutputStream  字符流 Reader Writer

从方向上可以分为:输入流InputStream Reader

                  输出流OutputStream Writer

 

字符流具体子类:

字符流是装门针对处理字符数据的流。

文件字符流 FileReader FileWriter

FileWriter:文件字符输出流。该流对象可以将内存中的数据以字符数据形式写到文件中。该类在创建对象时需要传入文件对象或是字符串路径。如果传入的文件在硬盘上不存在则会在创建流对象时创建文件。如果存在则覆盖该文件,从头开始入数据。

FileWrite常用方法:

 write(int ch)将一个字符写入文件中。

 write(char[] ch)将字符数组写入文件中。

 write(String str)将字符串写入文件中。

 

文件续写

要在已有数据文件里写入数据,就必须在创建FileWriter对象是用其续写文件模式的构造函数。

FileWriter(File file,boolean append)

当布尔类型参数为真时,FileWriter对象在创建对象时就不会覆盖文件。

FileReader 文件输入流

该类可以将文件中的字符数据写入内存中。

常用方法:

int read()读取一个字符到内存。返回读取字符的int表现形式,读到文件末尾返回-1.

int read(char[]ch)读取一个字符数组到内存,返回读取的字符数,如果读到文件末尾返回-1.

下面代码演示FileWriter与FileReader读取写出数据的方法。

package IO;

 

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

 

/*

 * 本例演示用FileReader与FileWriter两个对象复制文件。

 */

public class MyFileIO {

 

public static void main(String[] args) {

// TODO Auto-generated method stub

FileReader fr=null;

FileWriter fw=null;

try{

fr=new FileReader("c:/news.txt");

fw=new FileWriter("D:/news.txt");

char[]ch=new char[1024];

int len=0;

while((len=fr.read(ch))!=-1){

fw.write(ch,0,len);

fw.flush();

}

}catch(java.io.IOException e){

e.printStackTrace();

}finally{

if(fr!=null){

try {

fr.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

if(fw!=null){

try {

fw.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

 

}

注意在用FileWriter写数据时,必须调用flush()刷新流才能将流中的数据写到文件中。

 

字符流缓存技术 BufferedReader BufferedWriter

该技术是对字符流的性能与功能的加强与优化。

字符缓冲输入流:BufferedWriter 的常用方法

newLine()  写一个换行符。

 

字符缓冲输出流:BufferedReader 的常用方法

readLine()  一行一行的读取文件中的数据。

 

字符缓冲流体现了java的一种设计模式:装饰设计模式。

装饰设计模式是当想要对已有类进行功能增加时,可以定义类将已有类对象传入。基于其功能在对其功能进行增强。该类就被称为装饰类。

以下代码是演示用装饰设计模式定义一个自己的字符缓冲输入流,实现一行一行读取数据的方法。

 

 

public class MyBuffered {

//封装一个被装饰的流对象

private FileReader fr;

MyBuffered(FileReader fw){

this.fr=fr;

}

//自定义的readLine()方法

public String readLine() throws IOException{

StringBuilder sb=new StringBuilder();

int ch=0;

while((ch=fr.read())!=-1){

if(ch=='\r'){

continue;

}

if(ch=='\n'){

return sb.toString();

}

sb.append((char)ch);

}

return sb.toString();

}

}

 

字节流

除了文本文件,基于字符的数据可以用字符流进行读取。其他的电脑数据都是基于字节的。字节流就是针对字节数据进行存取的。

该流对象在使用上用字符流相似。

不同点:字节输出流不用像字符输出流那样,在用write方法将流写入数据后,再调用flush()将数据刷新到文件中。字节流不需要掉用flush()刷新流便可以将数据写出去。

FileInputStream:文件字节输入流特有方法

int available() 获取与流相关联的文件长度。

 

标准设备输入流与输出流

在java中的System类中提供了两个标准设备流。

System.in 键盘读取流 该流类型为InputStream

System.out 屏幕输出流 该流的类型为 PrintStream

可以利用这两种流读取键盘上的数据,和将内存上的数据打印到屏幕上。

System类的方法setIn(InputStream ins) setOut(printStream)可以改变两个流的源设备。

 

转换流 InputStramReader OutputStream

该类流是字节流与字符流的桥梁。

通过其的构造函数可以将字节流转换成相应的字符流。

以下代码将展示利用上述流读取键盘数据并打印到屏幕上。

并改变两个标准流的设备源

 

package IO;

 

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.io.IOException;

import java.io.PrintStream;

/*

 * 本例演示从键盘上接受数据并打印到屏幕上。学习俩个标准设备IO流

 * Sytem.in 键盘读取流 System.out屏幕打印流。

 * 并学习认识两种转换流:InputStreamReader 和OutputStreamWriter.

 * 学会改变两个标准设备IO流的源设备。

 */

public class JianPanjieShou {

 

public static void main(String[] args) {

// TODO Auto-generated method stub

BufferedWriter bw=null;

BufferedReader br=null;

try{//通过转换流将system.in System.out转换成字符流然后用缓冲流包装提高效率。

System.setIn(new FileInputStream("C:a.txt"));

bw=new BufferedWriter(new OutputStreamWriter(System.out));

br=new BufferedReader(new InputStreamReader(System.in));

String line=null;

//读取键盘输入。

while((line=br.readLine())!=null){

if(line.endsWith("over")){

bw.write(line.toUpperCase());

bw.newLine();

break;

}

bw.write(line.toUpperCase());

bw.newLine();

bw.flush();

}

}catch(IOException e){

e.printStackTrace();

}

finally{

if(bw!=null){

try {

bw.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

if(br!=null){

try {

br.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

 

}

注意:字符流的构造函数同时可以指定编码集。

 

File

File类是java中用于操作文件的类。

File类代表系统上的一个文件,但在创建File类对象时,并不会在电脑上创建一个文件,只有与之相关联的IO流写入数据时,或调用File类对象的创建文件方法时才会在电脑上创建文件。

File常用方法:

构造函数:File(File parent,String child)指定父目录对象和文件名。

File(String FileName)指定文件目录。可以是绝对路径或相对路径。

File(URI:url)根据指定的File:uri装换为一个抽象路径名。

 

创建

boolean createNewFile()创建一个文件,如果该文件对象表示的文件在系统上已存在则返回false.

boolean delete() 删除文件。

boolean deleteOnExit()设置该文件为JVM退出时被删除。

boolean mkdir() 创建一层文件夹。

boolean mkdirs()创建多层文件夹。

判断

boolean exist()测试该文件是否存在。

boolean isFile() 判断该file是否为文件。前提是文件必须存在

boolean isDirestory()判断该file是否为文件夹前提是文件夹必须存在

 

boolean isHidden() 判断该file是否是隐藏目录。

boolean isAbsolute() 是否是绝对路径。该文件可以不存在

 

获取:

String getName()  获取文件名

String getParant()  获取父路径。

String getAbsolute() 获取绝对路径名

long lastModified() 获取该文件最后修改时间

long length()  获取文件长度。

注意:getParant()返回绝对路径的父路径。如果该路径是相对对路径则返回null。如果相对路径中有上一层,则返回上一层目录。

boolean reNameTo(File)重命名。 

String[] list()列出文件夹下所有文件名。如果该对象非文件夹则返回null.如果该文件夹下没有文件则返回空。

File[] listFiles()  返回一组文件对象。

 String[] list(FilenameFilter filter) 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录

 String[] list(FilenameFilter filter) 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。  

FilenameFilter为一个文件名过滤器。其只需要实现一个方法boolean accept(File dir, String name) 

 两个参数dir为要过滤的文件夹,name为要过滤掉的文件名(文件名符合的规则)

 

下面代码演示如何列出某个文件夹上的所有文件名

package IO;

 

import java.io.File;

import java.io.ObjectInputStream.GetField;

 

public class DiGui {

public static void main(String[] args) {

File f = new File("D:/BaiduYunDownload/javaWeb");

myDiGui(f,0);

}

public static String getLevel(int level){

StringBuilder sb=new StringBuilder();

for(int i=0;i<level;i++){

sb.append("  |---");

}

return sb.toString(); 

}//该方法根据层级打印空格。

public static void myDiGui(File f,int level) {

System.out.println(getLevel(level)+f.getName());

level++;

File[] files = f.listFiles();

for (File files1 : files) {

if (files1.isDirectory()) {

myDiGui(files1,level);

} else {

System.out.println(getLevel(level)+files1.getName());

}

}

}

}

 

上面的代码还体现了一种算法思想:递归。

当函数内调用自身方法时,可以成这种算法思想为递归。

注意:递归要限定条件,不然就变成了无限循环。(在函数调用自身前,限定递归的条件。)当递归的条件为真时,程序会又进入自身方法。在内存中会重新开辟一个该方法的空间。所以要注意的内存溢出问题。当条件为假时,程序就会返回上一个自身方法内。

 

IO其他类

Properties

该类是系统配置类。是HashTable的子类,是IO流与集合框架的结合。可以直接将硬盘上的配置文件写到内存中。也可以将配置文件上的内容加载到Properties对象里。

方法:

setProperties()往Prpoerties里添加一个键值对元素。

Set  StringPropertyName()  将返回一个set集合,存放了Properties里所有的键。

load(InputStream)  将参数流相关联的配置文件加载到Properties集合内。

store(OutputStream out,String 注释)将ProperTies中的键值对元素写到文件中。

下面代码演示该类的使用。

 

package IO;

 

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

import java.io.PrintStream;

import java.util.Properties;

import java.util.Set;

 

/*

 * 本例演示用Properties读取配置文件和写数据到配置文件中。

 */

public class Myproperties {

public static void main(String[] args) {

//创建Properties集合对象并向集合中添加键值元素。

Properties p=new Properties();

p.setProperty("zhengwen", "red");

p.setProperty("beijing", "blue");

p.setProperty("icon", "green");

p.setProperty("bianchang", "3px");

p.setProperty("address", "www.baidu.com");

try {

/*p.store(new FileOutputStream("C:/peizhi.txt"), "");演示将集合中的元素写到文件中*/

//演示在配置文件中改变文件,将改变后的文件重新加载到集合,并打印到控制台。

p.load(new FileReader("C:/peizhi.txt"));

Set<String> set=p.stringPropertyNames();

for(String s:set){

System.out.println(s+"="+p.getProperty(s));

}//在屏幕上列出Properties集合元素

p.list(System.out);

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

 

打印流 PrintWriter 字符打印流 

       PrintStram  字节打印流

该类构造函数能接受的有:

1.File对象  2.字符串路径  3.字节输出流

4.字节输出流和boolean(是否需要自动刷新,必须要有换行的标志,要和println()方法结合使用)

 

合并流 SequenceInputStream

该流可以将多个字节输入流组合成一个大的字节输入流。该流将从第一个小流开始读取数据,一个接着一个读取数据,直到最后一个流的末尾返回-1.

构造函数:

SequenceInputStream(InputStream in1,InputStream in2)

接受两个字节流合并成一大的字节流。

SequenceInputStream(Enumeration<?extend InputStream>)

接受集合的枚举将集合中的字节流合并成一个大流。

以下代码演示SequneceInputStream流的使用

 

package IO;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

 

public class 切割文件 {

 

public static void main(String[] args) {

// TODO Auto-generated method stub

File f=new File("C:\\Users\\lenovo\\Pictures\\6.png");

spiltFile(f);

}

public static void spiltFile(File f){

FileInputStream in=null;

FileOutputStream out=null;

try{

in=new FileInputStream(f);

byte[]b=new byte[1024];

int count=30;//该变量的目的是让读取流读三十次后就重新创建一个新的输出流写数据到新的文件中

int len=0;

while((len=in.read(b))!=-1){

if(count%30==0){

out=new FileOutputStream("D:\\meimei"+(count-29)+".part");

}

count++;

out.write(b, 0, len);

}

}catch(java.io.IOException e){

}finally{

}

}

}

 

package IO;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.SequenceInputStream;

import java.util.ArrayList;

import java.util.Enumeration;

import java.util.Iterator;

import java.util.List;

/*

 * 本类演示多个文件合并。

 * 注意:重大发现创建FileOutputStream对象时,如果文件不从在,则会创建文件

 * 但该文件只能是两层目录 即 根目录(C: D:或 F:)\\文件名。如超过两层,则

 * 报FileNotFoundException

 */

import java.io.InputStream;

 

public class 合并文件 {

 

public static void main(String[] args) {

// TODO Auto-generated method stub

List<FileInputStream> list=new ArrayList<FileInputStream>();

try {

list.add(new FileInputStream("D:/meimei1.part"));

list.add(new FileInputStream("D:/meimei31.part"));

list.add(new FileInputStream("D:/meimei61.part"));

list.add(new FileInputStream("D:/meimei91.part"));

list.add(new FileInputStream("D:/meimei121.part"));

try {

HeBing(list);

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

//定义一个合并文件的方法,该方法接受一个list集合元素为InputStream的子类

public static void HeBing(List<? extends InputStream> l) throws IOException {

final Iterator<? extends InputStream> it = l.iterator();

FileOutputStream fon=new FileOutputStream("C:/m.png");

//创建一个合并流将参数集合里的字节流合并。

SequenceInputStream sis = new SequenceInputStream(

new Enumeration<InputStream>() {

 

@Override

public boolean hasMoreElements() {

// TODO Auto-generated method stub

return it.hasNext();

}

 

@Override

public InputStream nextElement() {

// TODO Auto-generated method stub

return it.next();

}

 

});

byte[] b = new byte[1024];

int len=0;

while((len=sis.read(b))!=-1){

fon.write(b,0,len);

}

sis.close();

fon.close();

}

}

 

ObjectInputStream和ObjectOutStream

这两个类能操作对象的流。其构造函数可以接受相对应的字节流。

ObjectOutStream可以将内存中的对象写到硬盘文件中。

ObjectOutStream可以将硬盘文件中的对象读到内存中。

注意:被上述的流对象操作的对象必须要实现可被序列化接口serizable。

why?

当一个类的对象要被写到硬盘上时,就会遇到这样的困境。写在硬盘上的对象是不会在改变的。而其所属类是有可能被修改的。当该类被改变了,ObjectInputStream将文件中的对象读到内存中时,编译器仍会认为该对象所属之前的类,这明显是错误的。

而实现Serizable接口就解决了这个风险。系统会自动为实现该接口的类生成序列号,序列号会随着类的改变而改变。编译器只需比较类与文件中的对象序列号就可以知道该对象与之前类是否仍属于从属关系。

关键字  transient  被其修饰的非静态成员是不能被序列化写入硬盘。但是静态是不能被序列化写入硬盘。

 

管道流

PipedInputStream和PipedOutStream

这两个流使用时是不能分离的兄弟。可以不需要中转站,直接进行读取数据。他们是这样工作的。PipedOutStream负责将数据写入,PipedInputStream负责将写入的数据读取出来。

该流对象多用于多线程。

创建对象时,两个流要么在构造函数里接受对方对象要么用空参数的构造函数创建对象。用connect()方法将两个管道流对象相连接。

下面代码演示管道流使用方法。

 

package IO;

 

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.PipedInputStream;

import java.io.PipedOutputStream;

 

/*

 * 本例是演示管道流的使用。注意管道流多用于在多线程中使用.

 * 管道流工作的入口应是pipedOutputStream。即先有负责读的管道流。

 * 然后负责读的管道流PipedInputStream读PipedOutputStream写入的数据。

 * 

 */

public class PipedStream {

 

public static void main(String[] args) {

// TODO Auto-generated method stub

PipedInputStream p1=new PipedInputStream();

PipedOutputStream p2=null;

try{

p2=new PipedOutputStream(p1);

}catch(IOException e){

e.printStackTrace();

}

new Thread(new read(p1)).start();

new Thread(new write(p2)).start();

}

 

}//定义读数据的类,内部封装PipedInputStream.来演示管道流读取数据的方法

class read implements Runnable{

private PipedInputStream p;

public read(PipedInputStream p) {

this.p=p;

// TODO Auto-generated constructor stub

}

@Override

public void run() {

while(true){

try {

byte[]b=new byte[1024];

int len=0;

len=p.read(b);

System.out.println(new String(b,0,len));

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

//定义写数据的类,内部封装PipedOutputStream.来演示管道流写取数据的方法

class write implements Runnable{

private PipedOutputStream p;

public write(PipedOutputStream p) {

this.p=p;

}

public void run() {

while(true){

try {

p.write("管道流哥们来了".getBytes());

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

 

RandomAcessFile 随机反问文件流

 

该流在IO体系中自称一派,直接继承与Object.可以对文件的随机读写。

特有方法:

      seek(Long pos)  设置指针位置

long  filePointer()获取指针位置

      skipBytes(Long pos)设置指针每次移动跳过的字节数。

 

构造函数

RandomAcessFile(File f,String model)

RandomAcessFile(String fileName,String model)

其中model表示该文件的反问权限 值可以为“r”“w”“rw”

代表该文件反问模式为可读、可写、可读可写。

如果模式为“r”在创建其对象时,如果文件不存在则创建该文件,存在,不会覆盖该文件。

 

编码

编码表

编码表是将日常人类熟悉的文字符号与二进制01数字组成的组合相对应形成的表。

ASCII    美国标准信息交换码表 用一个字节的七位表示一个     字符。

ISO889-1  欧洲信息交换码表。

GBK2312   中国信息交换码表。

GBK       GBK2312的升级版

Unicode   国际标准码表。

UTF-8     Unicode升级版。

java 中将字符串转换成字节即 编码 用字符串的getByte();

      将字节码转成字符串    解码 用字节码转成字符串 newString(byte[] b)

  -------<a href="http://www.itheima.com/"">android培训</a>、<a   href="http://www.itheima.com/" ">java培训</a>期待与您交流!----------