栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java高级特性(五)I/O编程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java高级特性(五)I/O编程

文件操作

File文件操作类
在java.io.File类中定义了File类,File类是唯一一个与文件本身(创建,删除,重命名)有关的类,要想进行File类操作,必须提供有完整的路径进行相应的处理
File类的基本处理
File类是Comparable接口的子类,所以File类对象是可以进行排序的,进行File类处理的时候需要为其设置访问路径,那么对于路径的配置主要通过File类的构造方法处理

构造方法:public File(Strin Pathname)设置要操作的完整路径
构造方法:public File(File parent,String child )设置父路径与子目录

创建新的文件:public boolean CreateNewFile()thows IOException:
判断文件是否存在:public boolean exists();
删除文件:public boolean delete();
范例:使用File类创建一个文件

public class myIO {
    public static void main(String[] args) throws Exception{
        File file=new File("G:\good\mode.txt");
        if (file.exists()){ //判断文件是否存在存在返回true,否中返回false
            System.out.println("文件已经存在");
            file.delete();//删除文件
            System.out.println("已经删除文件");
            file.createNewFile();
            System.out.println("已经重新创建");
        }else {
            file.createNewFile();//创建文件
        }
    }
}

项目开发常在Windows中开发,以Linux作为项目发布以保证生产环节的安全性,
开发时需要不同环境下的分隔符问题,windows分隔符”“,linux分隔符”/“,File类提供有一个常量:public static final String separator;
正常的路径编写

        File file=new File("G:"+File.separator+"good"+File.separator+"mode.txt");

在使用File类进行文件处理时注意:程序 — jvm —操作系统函数 — 文件处理,所以在进行同一文件的删除或者创建时可能会有延迟,最好的方案是不重名,
在进行文件创建时有一个重要的前提:文件的父路径必须首先存在,那么如何获取父路径呢?

如何获取父路径:public File getParentFile();
创建目录:public Boolean mkdirs();
public class myIO {
    public static void main(String[] args) throws Exception{
        File file=new File("G:"+File.separator+"good"+File.separator+"mode.txt");
       if (file.getParentFile().exists()){//父路径不存在时,创建父路径
           file.getParentFile().mkdir();
       }
       if (file.exists()){
           file.delete();
       }else {
           file.createNewFile();
       }
    }
}

这种判断并且创建父目录的操作很多情况下只需要一次,但是如果将这个判断一直停留在代码里面,那么会造成时间复杂度的提升,所以要想提升性能,就要保证目录已经创建,

获取文件信息
可以获取以下内容;

文件是否可读public Boolean canRead()
文件是否可写public boolean canWrite()
文件大小(返回的是字节长度)public long file.length()
最后一次修改日期时间public long lastModified()
判断是否是文件publi Boolean isFile()
是否是目录public boolean isDirectory()
列出目录内容:public File[] listFile()
import java.io.File;
class mathutil{//一个保留两位小数四舍五入的工具类
    public mathutil(){}
    public static  double round(double num ,int scale){
        return Math.round(Math.pow(10,scale)*num)/Math.pow(10,scale);
    }
}
public class myIO {
    public static void main(String[] args) throws Exception{
        File file=new File("G:"+File.separator+"good"+File.separator+"程序猿.png");
        System.out.println("文件是否可读"+file.canRead());
        System.out.println("文件是否可写"+file.canWrite());
        System.out.println("文件大小"+mathutil.round(file.length()/(double)1024/1024,2));
        System.out.println("文件最后一次修改时间"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(file.lastModified()));
        System.out.println("是否是文件"+file.isFile());
        System.out.println("是否是目录"+file.isDirectory());
    }
}

public class myIO {
    public static void main(String[] args) throws Exception{
        File file=new File("d:"+File.separator);
        if(file.isDirectory()){
            File result[]=file.listFiles();
            for (int x=0;x 

列出指定目录中的全部文件
现在可以设置任意一个目录的路径,而后将这个目录中所有的文件的信息全部列出,包括子目录中的全部文件,可以使用递归形式来完成

范例:完成
在其中添加合适的delete保证项目完整的佣金,

public class myIO {
    public static void main(String[] args) throws Exception {
        File file=new File("D:"+File.separator); //是一个目录
        listDir(file);
    }
    public static void listDir(File file){
           if(file.isDirectory()){
               File results[]=file.listFiles();
               if(results!=null){
               for (int x=0;x 

File操作案例:批量修改文件名称
编写程序,程序运行时输入项目名称,并把该目录下的所有文件名后缀修改为.txt,对于这个操作,必须做一些假设的约定,能够重命名的文件都是有后缀的,如果没有后缀的路径,则为其追加路径,如果有后缀的路径,则必须以最后一个”.“,进行截取

package main;


import java.io.File;

public class myIO {
    public static void main(String[] args) throws Exception {
       File file=new File("D:"+File.separator+"test");
       long start=System.currentTimeMillis();
       renameDir(file);
       long end=System.currentTimeMillis();
        System.out.println("本次用时"+(end-start));
    }
    public static void renameDir(File file){
        if (file.isDirectory()){
            File results[]=file.listFiles();
            if (results!=null){
                for (int x=0;x 

面试中可能会出现类似问题

字符流和字节流

file类能够操作文件本身,但不能操作文件的内容,I/O操作的核心是输入输出操作,对于程序而言,输入输出可能来自不同的环境,当通过电脑连接服务器上进行浏览的时候,实际上此时客户端发送一个信息,而后服务端接收到一个这样的信息后进行处理,对于服务器或者客户端而言实质上传递的是一种数据流的形式,所谓数据流指的就是字节数据,而对于这种流的处理在Java.io包里面提供有两类支持:
字节处理流:outputstream(输出字节流),Inputstream(输入字节流)
字符处理流:writer(输出字符流)reader(输入字符流)

所有的流操作都要采用如下统一的步骤进行,下面以文件处理流程为例:
如果现在要进行的是文件的读写操作,则一定要通过File类找到一个文件路径,
通过字节流或字符流的子类为父类对象实例化:
利用字节流或者字符流中的方法实现数据的输入与输出操作:
流的操作属于资源操作,资源操作必须进行关闭处理,

字节输出流outputstream
字节的数据是以byte类型为主实现的操作,在进行字节内容输出的时候可以使用outputstream类来完成,
public abstract classoutputstream extends object implements Closeable ,Flushable

CloseableFlushable
public interface closeable extends autoCloseable{ public void close() thows IOException ;}public interface Flushable{ public void flushable () thows IOException ;}

outputstream类定义的是一个的输出操作标准

方法名称作用
write(int b)输出单个字节数据
write(byte[] b)输出一组字节数据
write(byte[] b,int off,int len)输出部分字节数据

outputstream类毕竟是一个抽象类,要想获取实例化对象,应该通过子类向上转型完成,想要进行文件处理操作,则可以使用Fileoutputstream子类,
此时关注的fileoutputstream子类核心的关注点就是构造方法上:
(覆盖)构造方法:public Fileoutputstream(File file)thows FileNotFoundException
(追加)构造方法:public Fileoutputstream(File file,Boolean append)thows FileNotFoundException
范例:使用outputstream类实现内容的输出

public class myIO {
    public static void main(String[] args) throws IOException {
        File file=new File("G:"+File.separator+"good"+File.separator+"bbll.txt");
        if (!file.getParentFile().exists()){ //目录不存在的话创建目录
            file.getParentFile().mkdir();
        }
        OutputStream output=new FileOutputStream(file);
        String str="www.com"; //要输出的文字
        output.write(str.getBytes());  //将字符串变为字节数组
        output.close();//关闭资源
    }
}

文件并没有因为mkdir创建,而是程序执行后系统自动帮助用户自动创建的,outputstream子类有autocloseable的接口,所以可以实现自动关闭,

字节输入流 inputstream

在该类中有几个核心方法

方法名称作用
read()读取单个字节数据,读到底了,返回- 1
read(byte[] b)读取一组数据,返回的是读取的个数,如果没有数据读取返回-1
read(byte[] b ,int off,int len)读取一组字节数据

通过子类实例化抽象类inputstream,关注构造方法
对于字节输入流里面最麻烦的问题在于:使用read读取的时候只能以字节数组为主进行读取,
新方法 读取全部字节 readallbytes(),
如果要读取的内容很大时,这种读取会弄死你的程序,

字符输出流:writer
很多情况下字符串的输出是十分方便的,
writer类核心输出操作方法:
输出字符数组: public void write(char [] c) thows IOException
输出字符串:public void write(string str)thows IOEXception

public class myIO {
    public static void main(String[] args) throws Exception {
        File file = new File("G:" + File.separator + "good" + File.separator + "bbll.txt");
        if (file.getParentFile().exists()){
            file.getParentFile().mkdir();
        }
        Writer out=new FileWriter(file);
        String str="www.com2";
        out.write(str);
         out.append("good");
        out.close();
    }
}

使用writer输出的最大优势是可以直接利用字符串完成,writer是字符流,字符处理的优势在于中文数据上,

字符输入流:Reader
是一个抽象类,定义如下,
public abstract class reader extends objectimplements readable,closeable,
核心方法:
接收数据:public int read (char [] c) thows ioexception
实现数据读取

public class myIO {
    public static void main(String[] args) throws Exception {
        File file = new File("G:" + File.separator + "good" + File.separator + "bbll.txt");
       if (file.exists()){
           Reader in=new FileReader(file);
           char data[]=new char[1024];
           int len=in.read(data);
           System.out.println(new String(data,0,len));
           in.close();
       }
    }
}

字符流读取只能按照数组的形式来实现处理操作,

字节流和字符流的区别
在outputstream和write输出时都使用了close()方法,
当close方法不使用时outputstream能正常工作,writer不能正常工作,因为writer使用到了缓冲区,当使用close时会强制刷新缓冲区,这时候将内容输出,如果没有关闭,那么将无法进行输出操作,所以此时如果不关闭的情况下要想将全部内容输出可以使用flash()方法强制清空,
范例,使用writer,并强制清空,

public class myIO {
    public static void main(String[] args) throws Exception {
        File file = new File("G:" + File.separator + "good" + File.separator + "bbll.txt");
        if (file.getParentFile().exists()){
            file.getParentFile().mkdir();
        }
        Writer out=new FileWriter( file );
        java.lang.String str="ll";
        out.write( str );
        out.flush();
    }
}

转换流
可以实现字符流和字节流操作的功能转换,例如在进行输出的时候outputstream需要将内容变成字节数组后才能输出,而writer能直接输出字符串,这一点是方便的,需要提供一种转换机制实现转换,在java.io包里面提供了两个类;inputstreamReader,outputstreamWriter,

outputstreamWriterinputstreamReader
public class outputstreamWriter extends writer
定义public class outputstreamWriter extends writerpublic class outputstreamReader extends Reader
构造方法:public outputstreamwriter(outputstream out)public inputstreamReader(inputstream in)


转换程序结构

public class myIO {
    public static void main(String[] args) throws Exception {
        File file = new File("G:" + File.separator + "good" + File.separator + "bbll.txt");
        if (file.getParentFile().exists()){
            file.getParentFile().mkdir();
        }
        OutputStream output=new FileOutputStream( file );
        Writer out=new OutputStreamWriter( output );   //字节流变为字符流
        out.write( "nihao" );   //直接输出字符串。字符流适合于处理中文
        out.close();
    }
}

转换流的主要目的是知道有这样一种功能,知道有这样一中处理程序,通过之前的字节流和字符流的一系列的分析之后你会发现outputstream类有fileoutputstream直接子类,inputstream类有fileinputstream直接子类,但是filewriter和filereader类的继承关系,

filewriterfilereader
public class filewriter extends outputstreamwriterpublic class filereader extends outputstreamreader


实际上所谓的缓存指的是程序中间的一道处理缓冲区,

数据转换流程

实战:文件拷贝

在操作系统中有一个copy命令,在命令,这个命令的主要功能是可以实现文件的拷贝处理,现在要求模拟这个命令通过初始化参数输入拷贝文件的源文件路径与拷贝文件的目标路径实现文件的拷贝处理,

需求分析:
1.需要实现文件的拷贝操作,那么这种拷贝就可能拷贝各种类型的文件,所以肯定使用字节流,
2.在进行拷贝的时候有可能需要考虑到大文件的拷贝问题,
实现方案
方案一:使用inputstream将全部要拷贝的内容直接读取到程序里面,而后一次性的输出到目标文件,
缺点:如果拷贝文件很大,基本上程序就死了
方案二:采用部份拷贝,读取一部分就输出一部分,核心的操作是:
inputstream:read(byte[] b)
outputstream :write(byte[] b,int off,int len)
范例:实现文件拷贝处理,
第一版

package main;

import java.io.*;

public class JavaAPIDemo{
    public static void main(String[] args)throws Exception{
          if (args.length !=2){
              System.out.println("命令执行错误,执行结构,Java javaAPIDemo 拷贝源文件路径 拷贝目标文件路径");
              System.exit(1);
          }
          long start=System.currentTimeMillis();
          FileUtil fu=new FileUtil( args[0],args[1] );
        System.out.println(fu.copy()?"拷贝成功":"文件拷贝失败");
          long end=System.currentTimeMillis();
        System.out.println("拷贝完成的时间"+(end-start));
    }
}

class FileUtil{ //定义一个文件操作的工具类
    private File srcFile;
    private File desFile;
    public FileUtil(File srcFile,File desFile){
        this.desFile=desFile;
        this.srcFile=srcFile;
    }
    public FileUtil(String src,String des){
        this(new File( src ),new File( des ));
    }
    public boolean copy()throws Exception {
        if (!this.srcFile.exists()) {
            System.out.println("拷贝的源文件不存在");
            return false;
        }
        if (!this.desFile.getParentFile().exists()){
            this.desFile.getParentFile().mkdir();
        }
        byte data[]=new byte[1024];
        InputStream input=null;
        OutputStream output=null;
        try {
            input=new FileInputStream( this.srcFile );
            output=new FileOutputStream( this.desFile );
            int len=0;
              
            do {
             len=input.read(data);
                if (len!=-1){
                    output.write( data,0,len);}
            }while (len!=-1);
            return true;
        }catch (IOException e){
            throw e;
        }
          finally {
            if (input!=null){
                input.close();
            }
            if (output!=null){
                output.close();
            }
        }
    }
}

需要注意的是,以上的做法是属于文件拷贝到最原始实现,而从jdk1.9开始inputstream和reader类中都增加了转存的处理操作方法
inputstream:transTo(outputstream out)
reader:transTo(writer out)
范例:使用转存的方式处理

input.transTo(output);

此时千万要注意程序的运行版本问题,那么如果现在要求对该程序就行进一步扩展,可以实现一个文件目录的拷贝,还需要拷贝所有的子目录的拷贝,
自行思考

字符编码

计算机只认识0,1数据,如果想要描述一些文字就需要进行对这些文字进行编码,变成可以看见的中文,表现出内容一定需要解码,所以编码和解码肯定要采用统一的标准,不统一肯定要出现乱码,
常用的编码有以下几种:
GBK/GBK2312:国标编码,可以描述中文,其中GB2312只能描述简体中文,
ISO8859-1:国际通用编码,可以用其描述所有的文字信息,如果是象形文字则需要进行编码处理,
UNICODE:采用十六进制的方式存储信息,可以描述所有的文字信息,
UTF编码:象形文字部分使用十六进制编码,普通字母则采用ISO8859-1编码,他的优势是可以介于贷款,快速传输,是首选编码,
范例:返沪系统支持的属性

package main;
public class myIO {
    public static void main(String[] args){
        System.getProperties().list( System.out );
    }
}

"D:Program FilesJDK1.8binjava.exe" "-javaagent:E:ideaideasetupIntelliJ IDEA 2019.1.4libidea_rt.jar=62439:E:ideaideasetupIntelliJ IDEA 2019.1.4bin" -Dfile.encoding=UTF-8 -classpath "D:Program FilesJDK1.8jrelibcharsets.jar;D:Program FilesJDK1.8jrelibdeploy.jar;D:Program FilesJDK1.8jrelibextaccess-bridge-64.jar;D:Program FilesJDK1.8jrelibextcldrdata.jar;D:Program FilesJDK1.8jrelibextdnsns.jar;D:Program FilesJDK1.8jrelibextjaccess.jar;D:Program FilesJDK1.8jrelibextjfxrt.jar;D:Program FilesJDK1.8jrelibextlocaledata.jar;D:Program FilesJDK1.8jrelibextnashorn.jar;D:Program FilesJDK1.8jrelibextsunec.jar;D:Program FilesJDK1.8jrelibextsunjce_provider.jar;D:Program FilesJDK1.8jrelibextsunmscapi.jar;D:Program FilesJDK1.8jrelibextsunpkcs11.jar;D:Program FilesJDK1.8jrelibextzipfs.jar;D:Program FilesJDK1.8jrelibjavaws.jar;D:Program FilesJDK1.8jrelibjce.jar;D:Program FilesJDK1.8jrelibjfr.jar;D:Program FilesJDK1.8jrelibjfxswt.jar;D:Program FilesJDK1.8jrelibjsse.jar;D:Program FilesJDK1.8jrelibmanagement-agent.jar;D:Program FilesJDK1.8jrelibplugin.jar;D:Program FilesJDK1.8jrelibresources.jar;D:Program FilesJDK1.8jrelibrt.jar;E:ideaidesamethingnewsoutproductionIO" main.myIO
-- listing properties --
java.runtime.name=Java(TM) SE Runtime Environment
sun.boot.library.path=D:Program FilesJDK1.8jrebin
java.vm.version=25.231-b11
java.vm.vendor=Oracle Corporation
java.vendor.url=http://java.oracle.com/
path.separator=;
java.vm.name=Java HotSpot(TM) 64-Bit Server VM
file.encoding.pkg=sun.io
user.script=
user.country=CN
sun.java.launcher=SUN_STANDARD
sun.os.patch.level=
java.vm.specification.name=Java Virtual Machine Specification
user.dir=E:ideaidesamethingnews
java.runtime.version=1.8.0_231-b11
java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment
java.endorsed.dirs=D:Program FilesJDK1.8jrelibendorsed
os.arch=amd64
java.io.tmpdir=C:UsersADMINI~1AppDataLocalTemp
line.separator=

java.vm.specification.vendor=Oracle Corporation
user.variant=
os.name=Windows 10
sun.jnu.encoding=GBK
java.library.path=D:Program FilesJDK1.8bin;C:WINDOW...
java.specification.name=Java Platform API Specification
java.class.version=52.0
sun.management.compiler=HotSpot 64-Bit Tiered Compilers
os.version=10.0
user.home=C:UsersAdministrator
user.timezone=
java.awt.printerjob=sun.awt.windows.WPrinterJob
file.encoding=UTF-8
java.specification.version=1.8
user.name=Administrator
java.class.path=D:Program FilesJDK1.8jrelibchars...
java.vm.specification.version=1.8
sun.arch.data.model=64
java.home=D:Program FilesJDK1.8jre
sun.java.command=main.myIO
java.specification.vendor=Oracle Corporation
user.language=zh
awt.toolkit=sun.awt.windows.WToolkit
java.vm.info=mixed mode
java.version=1.8.0_231
java.ext.dirs=D:Program FilesJDK1.8jrelibext;C...
sun.boot.class.path=D:Program FilesJDK1.8jrelibresou...
java.vendor=Oracle Corporation
file.separator=
java.vendor.url.bug=http://bugreport.sun.com/bugreport/
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
sun.desktop=windows
sun.cpu.isalist=amd64

Process finished with exit code 0

项目中出现乱码问题就是编码和解码标准不统一,而最好解决方式,所有编码都使用”utf-8“,

内存操作流

在之前使用的全部都是文件操作流,文件操作流的特点,程序利用inputstream读取文件内容,程序liyongoutputstream向文件输出内容,所有操作都是以文件为终端的,

假设现在需要实现IO操作,可是又不希望产生文件,这时候就可以以内存为终端进行处理.,
在Java中提供了两类的内存操作流:
字节内存操作流:ByteArrayOutputstream,ByteArrayInputStream
字符内存操作流:charArraywriter,charArrayReader

下面以ByteArrayOutputStream和ByteArrayInputStream类为主进行内存的使用分析,
ByteArrayInputStream构造public ByteArrayInputStream(byte[]buf)
ByteArrayOutputStream构造:public ByteArrayoutputStream();

在ByteArrayOutputstream类里面有一个重要的方法,这个方法可以获取全部保存在内存流中的数据信息,该方法为:
获取数据:publicbyte[]toByteArray();
使用字符串的形式来获取:public String tostring();

f范例:利用内存实现一个小写字母转大写字母的操作,

public class myIO {
    public static void main(String[] args)throws Exception{
        String str="www.mldn.com";  //小写字母
        InputStream input=new ByteArrayInputStream(str.getBytes());  //将数据保存到内存流中
        //必须使用子类来调用子类自己的扩展方法
        ByteArrayOutputStream output=new ByteArrayOutputStream(  );
        int data=0;
        while ((data=input.read())!=-1){ //每次读取一个字节
            output.write( Character.toUpperCase( (char) data ) );  //保存数据
        }
        byte result[]=output.toByteArray();
        System.out.println(new String( result ));
        input.close();
        output.close();
    }
}

在最初的时候可以利用bytearrayoutstream实现大规模文本文件的读取,

管道


实现管道接收数据

class SendThread implements Runnable{
    private PipedOutputStream output;
    public SendThread(){
        this.output=new PipedOutputStream(  );
    }
    @Override
    public void run(){
      for (int x=0;x<10;x++){
          try {  // 利用管道实现数据的发送处理
              this.output.write( ("第"+(x+1)+"次信息发送"+Thread.currentThread().getName()+" www.mldn.cnn").getBytes() );
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
        try {
            this.output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public PipedOutputStream getOutput(){
        return output;
    }
}
class ReceiveThread implements Runnable{
    private PipedInputStream input;
    public ReceiveThread(){
        this.input=new PipedInputStream(  );
    }
    @Override
    public void run(){
           int len=0;
        ByteArrayOutputStream bos=new ByteArrayOutputStream(  );//所有的数据保存到内存输出流
           byte data[]=new byte[1024];
            try {
                while ((len=this.input.read(data))!=-1){
                    bos.write( data,0,len );
                }
                System.out.println(Thread.currentThread().getName()+"接收消息:"+new String( bos.toByteArray()));
            bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    public PipedInputStream getInput(){
        return input;
    }
}
public class myIO {
    public static void main(String[] args)throws Exception{
        SendThread send=new SendThread();
        ReceiveThread receive=new ReceiveThread();
        send.getOutput().connect( receive.getInput() ); //进行管道连接
        new Thread( send,"消息发送" ).start();
        new Thread( receive ,"消息接收线程" ).start();
    }
}

管道就类似于医院打点滴效果,一个只是负责发送,一个负责接收,中间靠一个管道连接

RandomAccessFile

对于文件内容的处理主要是通过input stream(reader),outputstream(writer)来实现的.利用这些类实现的,只能实现部分读取实现,
现在给你一个很庞大的文件,如果此时按照传统的IO操作是不能实现的,在java.io包里面就有一个RandomAccessFile类,这个类可以实现跳跃式读取,可以只读取中间的部分内容(前提:需要有一个完善的保存形式) 数据的保存位数要都确定好

RandomAccessFile类里面定义有如下的操作方法;
构造方法:public RandomAccessFile(File file,string mode);
文件处理模式:R,RW;
范例:实现文件的保存

public class myIO {
    public static void main(String[] args) throws IOException {
        File file=new File( "G:"+File.separator+"good"+File.separator+"bbll.txt" );//定义操作文件
        RandomAccessFile raf=new RandomAccessFile( file,"rw" );
        String names[]=new String[]{"zhansan","lisi","wangwu"};
        int ages[]=new int[]{30,15,16};
        for (int x=0;x 

RandomAccessFile最大的特点是在于数据的读取处理上,因为所有的数据是按照固定的长度进行的保存,所以读取的时候就可以进行调字节读取,
向下跳:public int skipBytes(int n);
向回跳:public void seek(long pos)

public class myIO {
    public static void main(String[] args) throws IOException {
        File file=new File( "G:"+File.separator+"good"+File.separator+"bbll.txt" );//定义操作文件
        RandomAccessFile raf=new RandomAccessFile( file,"rw" );
        {
            //读取“李四”的数据,跳过24位
            raf.skipBytes( 24 );
            byte[] data=new byte[8];
            int len=raf.read(data);
            System.out.println("姓名:"+new String( data,0,len ).trim()+"年龄:"+raf.readInt());
        }
        {
            //读取“王五”的数据,会跳12位
            raf.seek( 12 );
            byte[] data=new byte[8];
            int len=raf.read(data);
            System.out.println("姓名:"+new String( data,0,len ).trim()+"年龄:"+raf.readInt());
        }
        {
            //读取”张三”的数据,
            raf.seek( 0 ); //跳到首位
            byte[] data=new byte[8];
            int len=raf.read(data);
            System.out.println("姓名:"+new String( data,0,len ).trim()+"年龄:"+raf.readInt());
        }
        raf.close();
    }
}
打印流

现在要想通过程序实现内容的输出,核心的本质一定要依靠outputstream类完成,但是该类有一个极大的缺点,该类的数据输出操作功能有限:public voidwrite(byte [] b) ,所有数据一定要转换为字符串形式输出,项目中可以能输出的有long,dat额,double,这样的情况下必须将这些数据变成字节的形式来处理,这样的处理是十分麻烦的,往往是由开发者自行定义一些功能类来简化输出,

范例:通过工具类的方法实现打印输出流

package main;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

class printUtil implements AutoCloseable{  //实现一些常用数据的输出
    private OutputStream output; //核心是outputstream
    public printUtil(OutputStream output){      //由外部决定输出的位置
        this.output=output;
    }
    public void print(String str) {
        try {
            this.output.write( str.getBytes()); //输出字符串
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    public void println(String str){
       this.print( str+"rn" );
    }
    public void print(long num){
        this.print( String.valueOf( num ) );
    }
    public void println(long num) {
        this.println( String.valueOf( num ) );
    }
    @Override
    public void close() throws Exception {
           this.output.close();
    }
}
public class myIO {
    public static void main(String[] args)throws Exception{
        File file=new File( "G:"+File.separator+"good"+File.separator+"bbll.txt" );
        printUtil pu=new printUtil(new FileOutputStream(file) );
        pu.println( "姓名:小强子" );
        pu.print( "年龄:" );
        pu.println( 18 );
    }
}

在整个过程操作之中打印流的设计思想本质在于:提高已有类的功能,例如:outputstream是唯可以实现输出的操作标准类,应该以其为输出的根本,但其这个类输出的操作功能有限,不方便进行输出各个数据类型,那么就对他进行一层包装,所以此时采用的设计思想就是装饰设计模式.
但是既然所有的开发者都已经发现了原始中的outputstream功能的不足,所以在Java.io包里面提供了打印流:printStream,print’writer,

printstreamprintwriter
public class printstream extends Filteroutputstream implementsAppend able Closeablepublic class Printwriter extends writer
public printstream (outputstream out)public printwriter(output stream out)public printwriter(writer out)

使用printwriter实现数据的输出操作
范例数据输出

public class myIO {
    public static void main(String[] args)throws Exception{
        File file=new File( "G:"+File.separator+"good"+File.separator+"bbll.txt" );
        PrintWriter pu=new PrintWriter(new FileOutputStream(file) );
        pu.println( "姓名:小强子" );
        pu.print( "年龄:" );
        pu.println( 18 );
        pu.close();
    }
}
//淦,亏死我了写这么多后面来个这

从jdk15以后printwriter类里面追加有格式化输出的操作支持:public printwriter printf(string format ,object args)
格式化输出

public class myIO {
    public static void main(String[] args)throws Exception{
        File file=new File( "G:"+File.separator+"good"+File.separator+"bbll.txt" );
        PrintWriter pu=new PrintWriter(new FileOutputStream(file) );
        String name="小强子子";
        int age=18;
        double salary=7800.22;
        pu.printf( "姓名:%s,年龄:%d,收入:%.2f",name,age,salary);
        pu.close();
    }
}

比起直接使用output stream类,那么使用printwriter或者printstream类使用更加简单,要是程序内容输出的时候全部使用打印流,只有文件拷贝的时候才考虑outputstream输出流,

系统类对io操作的支持

提供了三个常量,与输入输出有关,
标准输出(显示器输出):public static final printstream out:
错误输出:public static final printstream err:
标准输入:public static final Inprintstream in:
out,err都是同种类型的,使用编译器使用system.err输出会使用红色字体,而system.out会使用黑色字体,in常量对应的是标准输入设备键盘输入,

bufferedreader缓冲输入流

bufferedreader类提供的是一个缓冲字符输入流的概念,也就是说,利用该类可以解决数据输入的问题,该类提供了一个重要的方法
读取一行数据:public stringreadline()thows IOException


利用该类实现键盘输入数据的标准化定义
实现键盘数据输入

public class myIO {
    public static void main(String[] args)throws Exception{
        BufferedReader input=new BufferedReader( new InputStreamReader( System.in ) ) ;
        System.out.println("请输入信息:");
       String msg=input.readLine();
        System.out.println("输入内容为:"+msg);
    }
}

实际开发过程中,输入输入数据都是通过string描述的,那么就方便了接收者进行处理
范例:接受输入并且验证

public class myIO {

    public static void main(String[] args)throws Exception{
        BufferedReader input=new BufferedReader( new InputStreamReader( System.in ) ) ;
        System.out.println("请输入您的年龄:");
       String msg=input.readLine();      //接收信息
       if (msg.matches( "\d{1,3}" )){ //是否由数字组成
           int age=Integer.parseInt( msg );
           System.out.println("年龄为:"+msg);
       } else{
           System.out.println("请不要随意输入,伤不起");
       }
    }
}

实际开发中,输入数据基本都是字符串,

scanner扫描类

java.util.Sanner类解决输入流的访问问题,替代了bufferedreader类,更好使用,scanner类里面有如下几种操作方法,
构造:public sscanner(inputstream source);
判断是否有数据:public boolean hasnext();
取出数据 :public next();
设置分隔符:public Scanner useDelimiter(string pattern);
范例:使用Scanner
实现键盘数据输入,

public class myIO {

    public static void main(String[] args)throws Exception{
        Scanner scan=new Scanner( System.in );
         System.out.println("请输入信息:");
        if (scan.hasNextInt()){
            int age=scan.nextInt();
            System.out.println("您的年龄:"+age);
        }else {
            System.out.println("傻逼");
        }
         scan.close();

    }
}

scanner输入数据还可以结合正则进行验证判断,
验证:判断是否为生日

public class myIO {

    public static void main(String[] args)throws Exception{
        Scanner scan=new Scanner( System.in );
        System.out.println("请输入您的生日:");
        if (scan.hasNext("\d{4}-\d{2}-\d{2}")){
            String age=scan.next("\d{4}-\d{2}-\d{2}");
            System.out.println("您的年龄:"+age);
            System.out.println("您的生日为"+ new SimpleDateFormat( "yyyy-MM-dd" ).parse( age ) );
        }
         scan.close();

    }
}

范例:使用scanner读取文件

public class myIO {
    public static void main(String[] args)throws Exception{
       Scanner scan=new Scanner( new File( "G:"+File.separator+"good"+File.separator+"bbll.txt" ) );
       scan.useDelimiter( "n" );//读取分隔符
       while (scan.hasNext()){
           System.out.println(scan.next(  ));
       }
       scan.close();
    }
}

在以后开发过程之中,如果程序需要输出数据一定使用打印流,输入数据一定使用scanner或者bufferedread,

对象序列化

Java序列化,
序列化定义:所谓序列化指的是将内存中保存的对象以二进制数据流的形式进行处理,可以实现对象的保存或者是网络传输,

然而并不是所有的对象都可以被序列化,在Java里面有一个强制性的要求:如果要序列化的对象所在的类一定要实现java.io.Serializable父接口作为序列化的标记,这个接口没有任何的方法,因为它描述的是一种类能力,
范例:定义一个可以被序列化的类

一个可以序列化的类
@SuppressWarnings( "serial" )
class Person implements Serializable{
    private String name;
    private int age;

    public Person(String name,int age) {
        this.name=name;
        this.age=age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

此时person类产生的每一个对象都可以实现二进制的数据传输,属于可以被序列化的程序类,serializable是序列化的核心,

序列化与反序列化
有序列化支持的类之后,如果想要实现序列化和反序列化的操作就可以利用以下两个类实现,

类名称:序列化: objectoutputstream反序列化:objectinputstream
类定义
构造方法
操作方法writeobject‘()readobject()

范例序列化与反序列化

package main;

import java.io.*;

public class myIO {
    private static final File SAVE_FILE=new File( "G:"+File.separator+"good"+File.separator+"medo.person" );
    public static void main(String[] args)throws Exception{
        saveobject( new Person(
                "小喷嚏",
                25
        ) );
        System.out.println(loadobject());
    }
    public static void saveobject(Object obj) throws Exception{
        ObjectOutputStream oos=new ObjectOutputStream( new FileOutputStream( SAVE_FILE ) );
        oos.writeObject( obj );
        oos.close();
    }
    public static Object loadobject() throws Exception{
        ObjectInputStream ois=new ObjectInputStream(( new FileInputStream(SAVE_FILE)));
       Object object=ois.readObject();   //反序列化
        ois.close();
        return object;
    }
}

@SuppressWarnings( "serial" )
class Person implements Serializable{
    private String name;
    private int age;

    public Person(String name,int age) {
        this.name=name;
        this.age=age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

Java中的对象序列化与反序列化必须使用内部提供的对象操作流,因为这里面牵扯到二进制数据格式,不能自定义类处理,如果想实现一组对象的序列化,可以用对象数组数组完成,
实际开发中很少见到objectoutputstream和objectinputstream类直接处理,因为会有一些容器帮助开发者实现,

transient 关键字
默认情况下当执行了对象序列化的时候会将类中的全部属性的内容进行全部的序列化操作,一些情况下,一些属性可能不需要序列化处理,这时候就可以在属性定义上使用transient关键字来完成了,

private transient String name;

在进行序列化处理的时候name属性的内容是不会被保存下来的,换言之,读取的数据name将是其对应数据类型的默认值,假设类之中一些是需要计算保存的属性内容往往是不需要被序列化的,这时候就可以使用该关键字了

javaIO编程案例

1.数字大小比较
编写Java程序,输入三个整数,并求出三个整数的最大值和最小值,

2.用户登录
完成系统登录程序,从命令行输入用户名和密码,如果没有输入用户名和密码,则提示输入用户名和密码,如果输入了用户名但是没有输入密码,则提示用户输入密码,然后判断用户名是否是mldn,密码是否是hello,如果正确则提示登陆成功,如果输入错误,显示登陆失败信息,用户再次输入用户名和密码,连续三次输入错误后系统推出。
3.投片选举
有一个班采用民主投票方法选举班长,每个人姓名代号分为张三,李四王五赵六,程序操作员将每张选票上所填的代号(1,2,3,4)循环输入电脑,然后所有候选人的的票信息显示出来,并显示当选者的信息,

goodgoodstayup

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/782717.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号