《java基础与案例开发详解》(四)
来源:互联网 发布:python可以建网站吗 编辑:程序博客网 时间:2024/05/18 21:42
- Java对文件和目录的操作
- File类的构造
- File类常用属性和方法
- 对文件目录操作
- 浏览目录中文件和子目录的方法
- Java IO原理
- Java中流分类
- IO流的抽象类
- InputStream常用方法
- OutStream常用方法
- Reader常用方法
- Writer常用方法
- 文件流
- 缓冲流
- 缓冲区流的分类
- 转换流
- 数据流
- 对象流
- 序列化版本
- 随机存取文件流
Java对文件和目录的操作
在java中,对物理存储介质中的文件和目录进行了抽象,使用java.io.File类代表存储介质中的文件和目录。
File类的构造
通常用文件或者目录路径来构造,这个路径可以是绝对路径也可以是相对路径。
File类常用属性和方法
代码示例:
File f = new File("E:\\Hello.java"); System.out.println(f.exists());//文件是否存在 System.out.println(f.isFile());//是文件吗 System.out.println(f.isDirectory());//是目录 System.out.println(f.getName());//获取文件名称 System.out.println(f.getAbsolutePath());//获取文件绝对地址 try { System.out.println(f.getCanonicalPath());//获取绝对路径的规范表示 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(f.lastModified());//获取文件最后修改时间 System.out.println(f.length());//获取文件大小,按字节算。 }
对文件、目录操作
浏览目录中文件和子目录的方法
代码如下:
//遍历文件是用的是递归 public static void ergodic(File f) { File[] files = f.listFiles(); for(File file:files) { System.out.println(file.getName()); if(file.isDirectory()) { ergodic(file); } } } //递归删除 public static void delete(File f) { if(f.isFile()) { f.delete();//如果是文件直接删除 }else {//如果是目录,需要先删除子文件 File[] files = f.listFiles(); for(File file:files) { delete(file); } } f.delete();//删除完子文件之后,最后删除文件夹。
Java IO原理
在java程序中要想获取数据源中的数据,需要在程序和数据源之间建立一个数据输入的通道,这样就能从数据源中获取数据了,如果Java程序中把数据写到数据源中,也需要在程序和数据源之间建立一个数据输出的通道。在java程序中创建流对象时,会自动建立这个数据输入通道,而创建输出流对象时会自动建立这个数据输出通道。
Java中流分类
1) 数据流方向
- 输入流
输出流
2) 数据传输单位
字节流
字符流
3)流功能
节点流:用于直接操作数据源的流。
- 过滤流:也叫过滤流,是对一个已经存在的流的封装和连接,提供更加强大的读写功能。
IO流的抽象类
InputStream常用方法
//is.read();//从输入流中读取数据的下一个字节,返回读到的字节值(这个字节值就是一个字节的十进制的值,比如读a,a是一个字符,就占一个字节,所以返回的值就是97),若遇到流结尾返回-1. //is.read(b);//从输入流中读取b.len个字节数据并存储到缓冲区b数组中,返回是实际读到的字节数。 //is.read(b, 0,b.length);//读取b.len个字节的数据,并从数组b的off位置开始写到数组中。
OutStream常用方法
//out.write(b);//将b.length个字节从指定的byte数组写入到输出流 out.write(97);//指定将规定的一个字节数写入此输出流,(相对应的你写97,就是a) //out.write(b, 0, b.length);//将指定的byte数组从偏移量off开始的len个字节写入此输出流。 out.flush();//刷新此输出流,并强制写出所有缓冲的输出字节。
Reader常用方法
主要以字符为单位进行处理。
a = reader.read();//读取单个字符,(请注意一个汉字就是一个字符),返回作为整数读取的字符,如果到末尾就是-1 //reader.read(c);//将字符读入数组中,返回读取的字符数 //reader.read(c, 0, c.length);//读取len个字符数据,并从数组的off位置开始写到数组中。
Writer常用方法
主要以字符为单位进行处理。
//w.write("老枪好帅");//写入字符串 w.write(c);//写入字符数组 w.write(c);//写入单个字符 w.write(c, a,c.length);//写入字符数据的一部分 w.write("", 0, len);//写入字符串的一部分 w.flush();//刷新该流的缓冲,全部写出来。
文件流
- FileInputStream
- FileOutputStream
- FileReader
- FileWriter
InputStream in = new FileInputStream("");//传入相应处理的文件路径 OutputStream out = new FileOutputStream(""); Reader reader = new FileReader(""); Writer writer = new FileWriter("");
上面是抽象的Io的实现,你在处理时,根据不同的文件进行相应的选择处理。
缓冲流
为了提高数据的读写速度,java提供了带缓冲流的流类,在使用这些带缓冲功能的流类,它会在内部创建缓冲区数组,在读取字节(创建字节数组)或者字符(创建字符数组)的时候,会把数据先读到缓冲区,然后在返回,在写入字节或者字符,会先把数据填充到内部缓冲区,然后一次性写到目标数据源中。
缓冲区流的分类
- BufferInputStream
- BufferOutputStream
- BufferReader
- BufferWriter
缓冲流属于过滤流,也就是说缓冲流不直接操作数据源,而是对直接操作数据源节点流的一个包装,增加功能。
下面给出操作字节字符缓冲流代码:
BufferedOutputStream bos = null; OutputStream out = null; InputStream in = null; BufferedInputStream bis = null; int i = 0; try { in = new FileInputStream("E:\\Hello.java"); out =new FileOutputStream("E:\\Hello1.java"); bos = new BufferedOutputStream(out); bis = new BufferedInputStream(in); while((i = bis.read())!=-1){//这里是从缓冲区上一次读一个 bos.write(i); } bos.flush(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(bos!=null) { try { bos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(bis!=null) { try { bis.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
Reader r = null; Writer w = null; BufferedReader br = null; BufferedWriter bw = null; String str = null; try { r = new FileReader("E:\\Hello.java"); w = new FileWriter("E:\\Hello2.java"); br = new BufferedReader(r); bw = new BufferedWriter(w); while((str = br.readLine())!=null) {//这个操作字符流和原来不一样,一次读一行。 bw.write(str); } bw.flush(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(br!=null) { try { br.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(bw!=null) { try { bw.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
在实际操作中,还是推荐使用第二种操作文件更方便。
注意在使用过滤流的过程中,它是对底层的节点流封装,所以在我们手动关闭了过滤流的时候,就不需要手动关闭节点流。
转换流
有时我们需要在字节流和字符流中进行转化,使用到InputStream Reader 和OutputStreamWriter。
- InputStream Reader
//InputStreamReader isr = new InputStreamReader(in);//传入字节流,转化成默认字符流读。 //InputStreamReader isr1 = new InputStreamReader(in, charsetName);//传入字节流,按照指定编码转化为字符流读。
用于将字节流中读取到的字节按字符集解码成字符。
- OutputStreamWriter
用于将要写入到字节流中的字符按照置顶字符集编码成字节。
OutputStreamWriter osw = new OutputStreamWriter(out);//传入字节流,转化成默认的字符流写入 OutputStreamWriter osw1 = new OutputStreamWriter(out, cs);//传入字节流,按照指定编码转化为字符流写
例子:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //从键盘上获取的是字符,通过转换流来变成字符流操作,更便捷。 try { while((content = br.readLine())!=null) { if(content.equalsIgnoreCase("e")) { break; }else { System.out.println(content.toUpperCase()); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
数据流
用于操作Java语言的基本数据类型的数据,主要有这两个类:DataInputStream和DataOutputStream。
代码如下:
DataOutputStream dis = null; DataInputStream is = null; InputStreamReader isr = null; BufferedReader br = null; String content = null; try { dis= new DataOutputStream(new FileOutputStream("E:\\data.txt")); dis.writeInt(87); dis.writeBoolean(true); dis.writeUTF("中国"); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { is = new DataInputStream(new FileInputStream("E:\\data.txt")); int a = is.readInt();//需要注意的是这里在读取的时候必须使用DataInputStream //否则出现乱码 boolean b = is.readBoolean(); String c = is.readUTF(); System.out.println(a); System.out.println(b); System.out.println(c); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
对象流
ObjectOutputStream和ObjectInputStream类是用来存储和读取基本类型数据或对象的过滤流,它的强大之处就是可以把Java中的对象写到数据源中,也能把对象从数据源中还原回来。用ObjectOutputStream类保存基本数据类型或者对象叫序列化,用ObjectInputStream类读取基本数据类型或者对象的机制叫做反序列化。ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量。
序列化:
//定义一个可以序列化的类public class Student implements Serializable{ private String name; private transient int age;//不能序列化的属性 private String sex;public Student(String name, int age, String sex) { super(); this.name = name; this.age = age; this.sex = sex;}public Student() { super(); // TODO Auto-generated constructor stub}public String getName() { return name;}public void setName(String name) { this.name = name;}public int getAge() { return age;}public void setAge(int age) { this.age = age;}public String getSex() { return sex;}public void setSex(String sex) { this.sex = sex;}}
在这个序列化中,它的成员变量不能被保存和读取。
序列化的好处在于,它可以将任何实现Serializable接口的对象转化为字节数据。这些数据可以保存在数据源中,以后仍可以恢复成原来的对象状态,即使这些数据通过网络也可以还原。
序列化和反序列化代码:
/*ObjectOutputStream out = null; try { out = new ObjectOutputStream(new FileOutputStream("E:\\data2.txt")); out.writeObject(new Student("laoqiang", 23, "男")); out.flush(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(out!=null) { try { out.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }*/ ObjectInputStream ois = null; try { ois = new ObjectInputStream(new FileInputStream("E:\\data2.txt")); Student s = (Student) ois.readObject(); System.out.println(s.toString()); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(ois!=null) { try { ois.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
序列化版本
凡是实现Serializable接口的类都有一个表示序列化版本标识的静态变量。用来表明类的不同版本之间的兼容性,默认情况下,如果没有直接定义这个变量,它的值是由java运行时根据累的内部细节自动生成,对于不同额java编译器,它的值可能相同也可能不相同。如果对类的源代码修改或者重新编译,该值会变。如果这时还用老版本的类来反序列化的,就会出错。我们建议,用户应该自己定一个,并且给它相应的值。
显式定义serialVersionUID的用途:
- 在某些场合,希望类的不同版本对序列化兼容,因此我们需要保证serialVersionUID相同。
- 在某些场合,不希望类的不同版本对序列化兼容,因此我们需要保证具有不同的serialVersionUID。
随机存取文件流
RandomAcessFile是一种特殊的流类,它可以在文件的任何地方读取或者写入数据,这是因为它提供文件指针,可以指定下次读取字节的位置。通过seek,可以将文件指针移动到文件内部的任意字节的位置。
随机文件存取流,提供两种方式可读(r),或者是同时读写(rw),不可以单独写。
随机存取文件执限于磁盘文件,不能访问来自网络,或者内存映像的流。
下面的是多线程下载文件:
private static final String URL= "www.baidu.com" ; private static int contentlength = 0;//资源的总字节数 private static int threadnumber = 10;//线程个数 private static int everythreaddownoadlength = 0;//每一个线程的需要下载的长度 private static int extra = 0; private static int start,end = 0;//记录每一个线程的开始和结束 private static File file = new File("E:\\data3.txt"); public static void main(String[] args) { try { URL url = new URL(URL); URLConnection conn = url.openConnection(); contentlength = conn.getContentLength(); everythreaddownoadlength = contentlength/threadnumber;//计算每个线程需要下载长度 extra = contentlength%threadnumber;//如果在上面计算每一个线程下载长度不能整除。 for(int i = 0;i<threadnumber;i++) { start = threadnumber*i; end = start+everythreaddownoadlength-1;//0~9,10~19,20~29 if(i == threadnumber-1) {//这里的意思,将不能平均的下载量全加给最后一个,因为剩余的不够分给一个线程 end = end+extra; } MyThread mt = new MyThread(start, end, file,URL); Thread t = new Thread(mt); t.start(); } } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}class MyThread implements Runnable{ private int start,end,length = 0; private File endfile = null; private String url = null; private BufferedInputStream bis = null; private byte[] b = new byte[2048]; public MyThread(int start, int end, File endfile,String url) { super(); this.start = start; this.end = end; this.endfile = endfile; this.url = url; } @Override public void run() { // TODO Auto-generated method stub URL url1 =null; URLConnection conn = null; try { url1 = new URL(url); conn = url1.openConnection(); } catch (MalformedURLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } RandomAccessFile raf = null; try { raf = new RandomAccessFile(endfile, "rw"); raf.seek(start);//将文件指针移动到线程开始的位置 bis = new BufferedInputStream(conn.getInputStream()); while((length=bis.read(b))!=-1) { raf.write(b, 0, length);//将资源写到目的的文件。 } System.out.println(Thread.currentThread().getName()+"下载好了"); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(raf!=null) { try { raf.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(bis!=null) { try { bis.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
大致思路:获取网路哦资源总长,按照线程个数,让每一个线程从不同开始位置下载。
- 《java基础与案例开发详解》(四)
- 《Java基础与案例开发详解》笔记(一)
- 《Java基础与案例开发详解》(五)
- 《Java基础与案例开发详解》(六)
- 软件开发-Java基础与案例开发详解
- Java基础与案例开发详解の抽象和封装
- 《java基础与案例开发详解》笔记(二)
- Java基础与案例开发详解の反射机制(完整)
- Java基础与案例开发详解のjava语言基础入门
- 原创图书《Java基础与案例详解》
- Java基础与案例开发详解のJava与C、C++、C#对比分析
- Java基础与案例开发详解のjava平台的体系结构
- Java基础与案例开发详解のjava技术的两个核心
- Java基础与案例开发详解のJava IO流操作
- 软件开发-Struts基础与案例开发详解
- 本人主编书籍《Java基础与案例开发详解》已经出版,海纳天下大侠捧场!!
- Java基础与案例开发详解の数组及常用技巧
- Java基础与案例开发详解の继承和多态
- DES算法的实现
- 【深入PHP 面向对象】读书笔记(八)
- 数据库的锁机制
- leetcode之链表逆序翻转类-----92/206 逆序 24/25/61/143 按规则翻转 86/234 双指针分治 19/82/83/203 按规则删除
- POJ 2965--The Pilots Brothers' refrigerator
- 《java基础与案例开发详解》(四)
- Mac下Nginx安装环境配置详解
- memcached的常用命令
- git使用流程及常用命令
- Java300StudyNote(8)-快速理解JDK&JRE&JVM
- Node.js学习-环境安装与配置
- 数字货币开发的底层技术如何实现执行智能合约代码
- 跳转语句----break和continue
- Map初始化及put过程(源码解析)