java I/O

1,I/O     java的输入输出系统,解决不同源端和接收端之间,多种不同形式的通信,(顺序,随机存取,缓存,二进制,按字符,按字节,按行)

     解决方案:创建不同类,装饰者模式

 

 

 1.1,磁盘操作--文件管理:File类

  • 可以代表某个文件,也可以表示一个目录下一组文件
  • 只表示文件和目录信息,但不表示文件内容

①:方法:

  • File(String path)  path如果是路径,表示的为目录。若是文件名,表示文件
  • File(String path,String name) path路径下的name文件
  • String getName() 获得文件名
  • String getPath()   获得文件路径
  • String getParent() 获得上一级目录
  • boolean isFile() 当前文件是否是文件
  • boolean isDirectory() 当前文件是否是文件夹
  • File[] listFiles() 返回当前目录(是文件夹)下的文件和目录
  • File[] listFiles(FileFilter filter) 返回当前目录下满足指定过滤器的文件和目录

②示例:递归列车一个目录下所有文件

    static int deep=0;
    public static void listAllFiles(File dir){
        if(dir==null||!dir.exists())
            return;
        for(int i=0;i<deep;i++)
            System.out.print("   ");
        if(dir.isFile()){
            System.out.println(dir.getName());
            return;
        }
        System.out.println(dir.getName());
        deep++;
        for(File file:dir.listFiles()){
            listAllFiles(file);
        }
        deep--;
    }

                     调用:

File file=new File("D:\\-_-\\春招\\1");
listAllFiles(file);

      输出:

 

③示例:文件过滤:

过滤器:Filter

自动义文件名过滤器:

static class Filter implements FilenameFilter{
String extend;
Filter(String extend){
this.extend=extend;
}
@Override
public boolean accept(File dir, String name) {
return name.endsWith("."+extend);
}
}
搜索方法:
public static void search(String filter){
File dir=new File("D:\\-_-\\春招\\1");
Filter filter1=new Filter(filter);
System.out.println(filter+"文件:");
File files[]=dir.listFiles(filter1);
for(File f:files){
if(f.isFile()){
System.out.println("文件名:"+f.getName());
}
}
}

调用结果:

search("pdf");

 

 

1.2,字节流

①InputStream和OutputStream,--抽象类

  • InputStream主要方法:

int read()  读取一个字节,0-255;若达到流末尾没有字节,返回-1

int read(byte[] b)  读取多个字节放到b中,返回读取字节数,流末尾返回-1

void close()   流操作结束,必须关闭

  • OutputStream主要方法:

void write(int b)   int32位4字节,将b的低8位写入输出流,高24位被忽略

void write(byte[] b)  将b.length个字节写入输出流。

void flush()  刷空输出流,

void close()  流操作完毕后必须关闭。

②InputStream子类: 

从文件输入,从Byte数组输入,管道

  • FileInputSream:文件输入流。它通常用于对文件进行读取操作
  • ByteArrayInputStream:  字符数组输入流,从Byte[]中以字节为单位读取,
  • PipedInputStream:管道字节输入流,它和PipedOutputStream一起使用,能实现多线程间的管道通信
  • ObjectOutputStream:用于序列化
  • FielterInputStream:  装饰者模式中处于装饰者,具体的装饰者都要继承它,所以在该类的子类下都是用来装饰别的流的,也就是处理类。
  • BufferedInputStream:  缓存流,对处理流进行装饰增强,内部有一个缓冲区,用来存放字节,缓存区存满后发出,不是一个字节或两个

字节这样发。效率高

  • DataInputStream:  数据输入流,用来装饰其他流,允许我们读取不同类型的基本数据类型以及String对象(readByte(),readFloat()等等。)

③OutputStream子类:

  • FileOutputstream
  • ByteArrayOutputStream
  • PipedOutputStream
  • ObjectOutputStream
  • FielterOutputStream
  • BufferedOutoutStream
  • DataOutputStream
  • PrintStream:      Systerm.in   Systerm.out

④装饰者模式   

  • 为对象动态添加功能
  • 装饰者(如FilterInputStream)与具体组件(如FileIputStream---BufferedInputStream)都继承至组件(如InputStream)。

具体组件的方法实现不需要依赖于其他对象,而装饰者组合了一个组件,这样可以装饰其他组件。

所谓装饰即扩展被装饰者的功能。

  • 例如实例化一个具有缓存功能的字节流对象,只需要在FileInputStream对象再套一层BufferedStream对象即可

FileInputStream fileInputStream = new FileInputStream(filePath);

BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);

⑤示例:实现文件复制:

public static void copyFile(String src,String dir)throws IOException{
FileInputStream in=new FileInputStream(src);
FileOutputStream out=new FileOutputStream(dir);

byte[] buffer=new byte[2*1024];
int cnt;
while ((cnt=in.read(buffer,0,buffer.length))!=-1){
out.write(buffer,0,cnt);
}
in.close();
out.close();
}

 调用结果:       

String src=".\\test.txt";
String dir="test2.txt";
copyFile(src,dir);

 

 

 

 ⑥示例:使用字节缓存流:

  • BufferedIputStream(InputStream in)  通过一个底层输入流in对象创建缓冲流对象,缓冲区大小是默认的,默认值8192
  • BufferedOutputStream(OutputStream out)  通过一个底层输出流 out 对象创建缓冲流对象,缓冲区大小是默认的,默认值 8192。
public static void bufferCopyFie(String src,String dir)throws IOException{
FileInputStream in=new FileInputStream(src);
FileOutputStream out=new FileOutputStream(dir);
BufferedInputStream bin=new BufferedInputStream(in);
BufferedOutputStream bout=new BufferedOutputStream(out);

long startTime=System.nanoTime();
byte[] buffer=new byte[1024];
int len=bin.read(buffer);

while (len!=-1){
bout.write(buffer,0,len);
len=bin.read(buffer);
}
long time=System.nanoTime()-startTime;
System.out.println("缓冲器耗时: "+(time/1000000.0)+"毫秒");
}
public static void copyFile(String src,String dir)throws IOException{
FileInputStream in=new FileInputStream(src);
FileOutputStream out=new FileOutputStream(dir);

long startTime=System.nanoTime();
byte[] buffer=new byte[1024];
int cnt;
while ((cnt=in.read(buffer,0,buffer.length))!=-1){
out.write(buffer,0,cnt);
}
in.close();
out.close();
long time=System.nanoTime()-startTime;
System.out.println("无缓冲器耗时: "+(time/1000000.0)+"毫秒");
}

                 运行结果:

String src=".\\test.txt";
String dir="test2.txt";
copyFile(src,dir);
bufferCopyFie(src,dir);

 

 有缓冲区效率高

 1.3,字符流

  • 为了国际化,java采用Unicode字符,为双字节字符。

①字符编码:

编码:编码是从一种形式或格式转换为另一种形式的过程也称为计算机编程语言的代码简称编码

计算机中储存信息的最小单位是一个字节,即8个bit.

  • ASCII码:共有128个,用一个字节的低7位表示。
  • ISO8859-1:  在ASCII码的基础上涵盖了大多数西欧的语言字符,仍是单字节编码,总共表示256个。
  • GB2321:全称为《信息交换用汉字编码字符集基本集》双字节编码,
  • GBK:《数字交换用汉字编码字符集》,单,双,四字节编码,与GB2312编码兼容。扩展了繁体字等
  • UTF-16:具体定义了Unicode字符在计算机中的存取方法,采用2字节表示Unicode转换格式。定长编码
  • UTF-8:采用一种变长技术,不同字符可以1-6字节。

②String编码:

String s="一二三";

byte[] bytes=s.getBytes("UTF-8");

String s1=new String(bytes,"UTF-8");

 

③字符流与字节流的区别

  • 字节流没有缓冲区,是直接输出的,而字符流是输出到缓冲区的。因此在输出时,字节流不调用colse()方法时,

信息已经输出了,而字符流只有在调用close()方法关闭缓冲区时,信息才输出。要想字符流在未关闭时输出信息,

则需要手动调用flush()方法。

  • 读写单位不同,字节流以字节(8bit)为单位,字符流以字符为单位。
  • 处理对象不同,字节流是处理所有类型数据(如图片,视频等),而字符流只能处理字符类型的数据。

只处理纯文本数据,优先考虑字符流,除此之外使用字节流。

④字符流与字节流转换

  • InputStreamReader(InputStream in), 将字节流in转换位字符流,默认编码
  • InputStreamReader(InputStream in,String charsetName) ,将字节流in转换位字符流,charsetName是指定字符集

ASCII,ISO-8859-1,UTF-8,UTF-16等。如果字符集不支持会抛出UnsupportedEncodingException异常。

  • OutputStreamWriter(OutputStream out)  将字节流out转换位字符流,默认字符集
  • OutputStreamWrite(OutputStream out,String charsetName)  将字节流out转换为字符流对象,charsetName是指定字符集

如果字符集不支持会抛出UnsupportedEncodingExseption.

⑤Reader和Writer---抽象类

Reader主要方法:

  • int read()   读取一个字符,0-65535(0x00-oxffff)。达到文件末尾返回-1.
  • int read(char[] c) 将字符读入char数组中,返回实际读取字符数。末尾返回-1.
  • void close()  流操作结束后必须关闭。

Writer主要方法:

  • void write(int c) 将int c写入输出流,int4字节,写入低16位,高16位忽略
  • void write(char[] c)  将字符数组c写入输出流
  • void write(char[] c,int off,int len)  把字符数组c从下标off开始的len个字符写入输出流
  • void write(String s)  将s中的字符写入输出流
  • void write(String s,int off,int len)  把字符串s从下标off开始的len个字符写入输出流
  • void flush()  刷空输出流,,并输出所有被缓存的字符。
  • void cloae()  流操作结束必须关闭

Reader子类

  • CharAraryReader:
  • StringReader:
  • PipedReader:
  • BufferedRead:并不是Filter子类。
  • InputStreamRead:
  • FilterRead:

Writer子类:

  • CharArrayWriter
  • StringWriter
  • PipedWriter
  • BufferedWriter
  • OutStreamWriter
  • PriterWriter
  • FilterWriter

 ⑥示例:从文件逐行输出内容

public static void readFile(String path)throws IOException{
FileReader fileReader=new FileReader(path);
BufferedReader bfileReader=new BufferedReader(fileReader);

String line;
while((line=bfileReader.readLine())!=null){
System.out.println(line);
}
bfileReader.close();
}

⑦示例:文件复制:

public static void copyFileReader(String src,String dir)throws IOException{
FileReader in=new FileReader(src);
FileWriter out=new FileWriter(dir);
char[] buffer=new char[10];

int len=in.read(buffer);
while(len!=-1){
String str=new String(buffer);
out.write(buffer,0,len);
len=in.read(buffer);
}
}

使用缓冲:

readLine()方法丢掉 换行符

写完调用float()方法才会将缓冲区信息写入

 

public static void bufferCopyFileReader(String src,String dir){
try{

FileReader in=new FileReader(src);
FileWriter out=new FileWriter(dir);
BufferedReader bin=new BufferedReader(in);
BufferedWriter bout=new BufferedWriter(out);


long startTime=System.nanoTime();
String line=bin.readLine();
while (line!=null){
bout.write(line);
bout.newLine();----readLine()方法丢掉换行符,这里补上;
//System.out.println(line);
line=bin.readLine();

}
bout.flush();----flush!!!!!
long time=System.nanoTime()-startTime;
System.out.println("缓冲器耗时: "+(time/1000000.0)+"毫秒");
}catch (FileNotFoundException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
}

 

 1.4,对象操作

序列化:序列化就是将一个对象转换成字节序列,方便储存和运输。

               保存对象信息,---程序停止运行对象就消失了。

               实现轻量级持久性,意味着对象的生命周期不取决于程序是否执行。

  • 序列化:ObjectOutputStream.writeObject()
  • 反序列化:ObjectInputStream.readObject()

1.5,NIO

  • JDK1.4引入NIO为了提高速度,以及融合进java.io.*中。
  • 通道与缓存器:速度提高来自于使用更接近操作系统的I/O,:通道与缓存器。
  • I/O以流的方式处理数据,而NIO面向块以处理块的方式处理数据。
  • IO是阻塞的,NIO是非阻塞的。

①通道:Channel,

  • 通道是对原IO中流的模拟,可以通过它读取和写入数据。
  • 通道与流不同之处在于,流只能在一个方向上移动,(一个流必须是InputStram或者OutputStream的子类,而通道是双向的) 
  • 通道的类型:

FileChannel:从文件中读取数据

DatagramChannel:通过UDP读写网络上数据

SocketChannel:通过TCP读写网络中数据

ServerSocketChannel: 可以监听新进来的TCP连接,对每一个新进来的连接都会创建一个SocketChannel.

②缓冲区:

  • 发送给一个通道的所有数据都必须首先放在缓冲区中,同样的,从通道中读取任何数据都先读到缓冲区,
  • 缓冲区实际上是一个数组,提供了对数据的结构化访问,而且可以跟踪系统的读写进程。
  • 缓冲区类型:

ByteBuffer,CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer,DoubleBuffer

  • 缓冲区状态变量:

capicity:最大容量

position:当前已读写的字节数

limit:还可以读写的字节数

 

  • 状态变量改变过程:

<1>,新建一个大小为8的字节缓冲区,此时positon为0,而limit=capacity=8,capacity不会改变

 

 

<2>,从通道中取出5个字节数据写入缓冲区中,此时position为5,limit保持不变

 

 

<3>,在将缓冲区的数据写到输出通道之前,需要先调用filp()方法,这个方法将limit设置为当前poosition,并将position设置为0

 

 

<4>,从缓冲区中取出4个字节输出到缓冲中,此时position为4

<5>,最后需要调用clear()方法来清空缓冲区,此时position和limit都设为初始位置

 

 ③文件NIO示例:文件复制:

public static void fastCopy(String src,String dir)throws IOException{
FileInputStream fin=new FileInputStream(src);
FileChannel fcin=fin.getChannel();
FileOutputStream fout=new FileOutputStream(dir);
FileChannel fcout=fout.getChannel();
ByteBuffer buffer =ByteBuffer.allocateDirect(1024);
while(true){
int r=fcin.read(buffer);
if(r==-1){
break;
}
buffer.flip();
fcout.write(buffer);
buffer.clear();
}
}

 ④选择器,Selector,网络通信中NIO

......

 

 

参考:

Java-IO流

技术面试必备基础知识 CyC2018.pdf

java编程思想

java从小白到大牛精简版

电子书(pdf)获取途径:史上最全的 Java 学习资料,PDF 电子书大合集

 

 

 

 

posted on 2020-11-03 21:09  呵呵哒9876  阅读(197)  评论(0编辑  收藏  举报