JAVA IO
java.io.File类
java对文件和目录的操作
java.io.File类用于表示文件或者目录。
对于File类的对象的操作实际就为对存储介质中的文件和目录的操作。
File类的文件操作与操作系统平台无关。
-
构造方法
public File(String pathname)以pathname为路径创建File对象。
-
常用属性
public static final String separator: 存储当前系统的路径分隔符。UNIX:'/',Windows:'\'。为了跨平台文件路径应用这个属性代替。
-
访问属性的方法
-
public boolean canRead()
:判断文件是否可读 -
public boolean canWrite()
: 判断文件是否可写 -
public boolean exits()
: 判断文件是否存在 -
public boolean isDirectory()
:判断是否是目录 -
public boolean isFile()
: 判断是否为文件 -
public boolean isHidden()
: 判断文件是否隐藏 -
public long lastModified()
: 返回最后修改的时间 -
public long length()
: 返回文件以字节为单位的长度 -
public String getName()
:获取文件名 -
public String getPath()
:获取文件的路径 -
public String getAbsolutePath()
:获取此文件的绝对路径名。 -
public String getCanonicalPath()
:获取此文件的规范路径名。 -
public File getAbsoluteFile()
: 得到绝对路径规范表示的文件对象。 -
public String getParent()
:得到文件的父目录路径名 -
public URL toURL()
:返回此文件的统一资源标识符名public static void main(String[] args) throws IOException { File file = new File("D:\IOTest\source.txt");//指定目录要存在改文件 }
-
-
对文件的操作
public boolean createNewFile()
: 不存在时常见此文件对象所代表的空文件。public boolean delete()
:删除文件。必须目录为空才能删除public boolean mkdir()
:创建此抽象路径指定的目录。public boolean mkdirs()
: 创建此抽象路径指定的目录,同时创建父目录public boolean renameTo(File dest)
:重新命名为此抽象路径表示的文件
-
浏览目录中的文件和子目录方法
public String[] list()
: 返回此目录中的文件和目录名的数组public File[] listFiles()
: 返回此目录中的文件和目录的File实例数组public File[] listFiles(FilenameFilter filter)
: 返回此目录中满足指定过滤器的文件和目录
public static void main(String[] args) throws IOException{ File dir1 = new File("D:/IOTest/dir1"); if (!dir1.exists()) dir1.mkdir();//不存在就创建 File dir2 = new File(dir1, "dir2");//以dir1为父目录 名字为dir2 File dir4 = new File(dir1, "dir3/dir4");//以dir1,dir3为父目录 创建名字为dir4的目录 File file = new File(dir2, "test.txt"); if (!file.exists()) file.createNewFile();//不存在就创建 deleteAll(dir1);//删除目录 } public static void deleteAll(File file){ if (file.isFile()) { file.delete();//直接删除文件 return; } //是目录 则递归删除子目录和子文件 File[] lists = file.listFile(); for (int i = 0; i < lists.length; i++) { deleteAll(list[i]);//则递归删除子目录和子文件 } System.out.println("删除目录:"+ file.getAbsolutePath()); file.delete(); }
java IO原理
从数据源读数据时就要开启一个到数据源的流。
方便处理数据的输入输出。
流式结构
- 按数据流向
- 输入流:程序可能从中读取数据的流
- 输出流:程序可能从中输出数据的流
- 按数据传输单位
- 字符流:传输单位为字符
- 字节流:传输单位为字节
- 按流的功能
- 节点流:用于直接操作数据源的流
- 过滤流:处理流,对一个已经存在流的连接和封装,读写功能更强大
java.io包中四种抽象流类:
- 字节流:
- InputStream
- OutputStream
- 字符流:
- Reader
- Writer
InputStream和OutputStream
-
InputStream
以字节为单位从数据源中读取数据
public abstract int read() throws IOException
: 从输入流中读取数据的下一个字节,返回读到的字节值。流的末尾返回-1public void close() throws IOException
:关闭输入流并释放系统资源
-
OutputStream
以字节为单位向数据源写数据
public abstract void write(int b) throws IOException
:将指定的字节写入输出流public void write(byte[] b) throws IOException:
将b.length个字节从指定的byte数组写入此输出流public void flush() throws IOException
:刷新此输出流,并强制写出所有缓冲的输出字节public void close() throws IOException
:关闭输入流并释放系统资源
Reader和Writer
-
Reader
以字符为单位从数据源中读取数据
- public abstract int read() throws IOException: 从输入流中读取数据的字符,返回读到的字符值。流的末尾返回-1
- public void close() throws IOException:关闭输入流并释放系统资源
-
Writer
以字符为单位向数据源写数据
public abstract void write(int b) throws IOException
:将指定的字符写入输出流public void write(char[] cbuf) throws IOException
: 写入字符数组public void write(String str) throws IOException
:写入字符串public void flush() throws IOException
:将缓冲数据全部写到目的地public void close() throws IOException
:先刷新再关闭
文件流
FileInputStream、FileOutputStream、FileReader、FileWriter四个文件流。
-
FileInputStream、FileOutputStream
import java.io.* public static void main(String[] args) { FileInputStream fin = null; try { // 第一步:创建一个FileInputStream对象 fin = new FileInputStream("D:\IOTest\source.txt"); System.out.println("可读取的字节数" + fin.available()); //第二步:按字节读数据,返回的是读到的字节 int i = read(); while(i != -1) { System.out.println((char)i); i = fin.read(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (null != fin) fin.close();//关闭输入流 } catch (IOException e) { e.printStackTrace(); } } }
Java字符采用Unicode,汉字占用两个字节,英文字符占一个用字节流读取会出乱码问题。
import java.io.* public static void main(String[] args) { FileInputStream out = null; try { //1.建立连接 out = new FileInputStream("D:\IOTest\source.txt"); //2.写数据 out.write("#"); out.write("hello word".getBytes());//字符串转换为字节数组 out.write("你好".getBytes());//字符串转换为字节数组 //3.刷新输出流 out.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (null != out) out.close();//关闭输入流 } catch (IOException e) { e.printStackTrace(); } } }
IO流类的close方法会释放占有的系统资源,用来操作二进制文件比较合适,图片,声音,视频等二进制文件。
-
FileReader、FileWriter
以字符为操作单位的文件输入流和文件输出流。
常用于操作字符文本文件。
//实现字符文本的复制 import java.io.* public static void main(String[] args) { FileReader fr = null; FileWriter fw = null; int c = 0; try { fr = new FileReader("D:\IOTest\source.txt"); fw = new FileWriter("D:\IOTest\result.txt"); while((c = fr.read()) != -1) { fw.write(c); } fw.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (null != fw) fw.close();//关闭输入流 if (null != fr) fr.close();//关闭输入流 } catch (IOException e) { e.printStackTrace(); } } }
为了更高的效率可以一次提取一个字节数组和写入一个字节数组。
int length = 0;//字符串长度 char []cbuf = new char[8192]; while((length = fr.reader(cbuf)) != -1) { fw.write(cbuf, 0, length);//一次性写入 }
缓冲流
为了提高读写速率,提供带缓冲功能的流类,内部创建一个缓冲区数组。读取数据时,先把数据填充到该内部缓冲区,然后再返回;在写入数据前先放到缓冲区再一次性写入到目标数据源。
- BufferedInputStream 和 BufferedOutputStream:针对字节的缓冲输入和输出流
- BufferedReader和BufferedWriter:针对字符的缓冲输入和输出流
属于过滤流,不直接操作数据源,是对直接操作数据源的节点流的一个包装。
//用缓冲流来改写字符文本复制功能
public static void main(String[] args) {
BufferedReader br = null;
BufferedReader bw = null;
try {
//创建缓冲流对象:是过滤流,是对节点流的包装
br = new BufferedReader(new FileReader("D:\IOTest\source.txt"));
bw = new BufferedWriter(new FileWriter("D:\IOTest\source.txt"));
String str = null;
while ((str = br.readLine()) != null) { // 每次读取一行字符
bw.write(str); //一次写入一行字符串
bw.newLine(); //写入行分隔符
}
bw.flush();
}
}
关闭过滤流时会自动关闭所包装的底层节点流。
转换流
在字节和字符流之间转换。
InputStreamReader和OutputStreamWriter。
-
InputStreamReader
将字节流中读取到的字节按指定字符集解码成字符,需要和InputStream套接
InputStreamReader(InputStream in)
:使用默认字符集的InputStreamReaderInputStreamReader(InputStream in, String charsetName)
:使用指定字符集的InputStreamReader
-
OutputStreamWriter
将要写入字节流的字符按指定字符集编码成字节,需要和OutputStream套接
OutputStreamWriter(OutputStream in)
:使用默认字符编码的OutputStreamWriterOutputStreamWriter(OutputStream out, String charsetName)
:使用指定字符编码的OutputStreamWriter
public static void main(String[] args) {
System.out.println("输入信息:按e或exit退出");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = null;
try {
while(s = br.readLine() != null) {
if (s.equalsIgnoreCase("e")||s.equalsIgnoreCase("exit")) {
System.out.println("安全退出!!");
break;
}
System.out.println("-->:" + s.toUpperCase());
System.out.println("输入信息:按e或exit退出");
}
} catch {//异常处理
...
}
}
先把字节流包装成字符流,为了进一步提高效率,又把它包装成缓冲流。
数据流
为了方便操作java语言的基本数据类型的数据,可以使用数据流。
DataInputStream和DataOutputStream分别来读写出基本数据类型
public final boolean readBoolean()
: 从输入流中读取一个布尔型的值。public final byte readByte()
: 从输入流中读取一个8位的字节public final char readChar()
: 读取一个16位的Unicode字符public final float readFloat()
: 读取一个32位的单精度浮点数public final double readDouble()
: 读取一个64位的双精度浮点数public final short readShort()
: 读取一个16位的短整数public final int readInt()
: 读取一个16位的短整数public final long readLong()
: 读取一个64位的长整数public final void readFully(byte[] b):
从当前输入流中读取b.length个字节到该字节数组public final void readFully(byte[] b, int off, int len)
: 从当前数据流中读取len个字节到字节数组public final String readUTF()
: 读取一个UTF格式字符组成的字符串public int skipBytes(int n)
: 跳过n字节
public static void main(String[] args) {
DataOutputStream dos = null;
try {
//创建连接到指定文件的数据输出流对象
dos = new DataOutoutStream(new FileOutputStream("d:\IOTest\destData.dat"));
dos.writeUTF("ab 中国");
dos.writeBoolean(false);
dos.writeLong(12345678L);
}
}
打印流
PrintStream和PrintWriter都属于打印流,提供一系列的print和println方法,可以实现将基本数据类型的数据格式转换成字符串进行输出。
PrintStream和PrintWriter不会抛出IOException异常
public class void main(String[] args) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File("d:\IOTest\text.txt"));
} catch(FileNotFoundException e) {
e.printStackTrace();
}
//创建打印输出流,设置为自动刷新模式(写入换行或字节'
'都会刷新输出缓冲区)
PrintStream ps = new PrintStream(fos, true);
if (ps != null) {
//把标准输出流(控制台输出)改成文件
System.setOut(ps);
}
for (int i = 0; i <= 255; i++) {
System.out.print((char)i);
if (i % 50 == 0) {
System.out.println();//换行
}
}
ps.close();
}
对象流
ObjectOutputStream和ObjectInputStream类是用于存储和读取基本数据类型或对象的过滤流,可以把Java 的对象写入到数据源中,也能把对象从数据源中还原回来。
用ObjectOutputStream保存基本数据类型或对象的机制叫做序列化。
用ObjectInputStream读取基本数据类型或对象的机制叫做反序列化。
ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量,能被序列化的对象所对应的类必须实现java.io.Serializable这个标识性接口。
public class Student implements java.io.Serializable {
private int id;
private String name;
private transient int age; //在序列化的时候不会被保存和读取
public Student(){}
public student(int id, int age, String name) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {return id;}
public int getAge() {return age;}
public String toString() {return "id="+id ,",name="+name,",age="+age;}
}
//创建一个学生对象并序列化到一个文件objectSeri.dat
public static void main(String[] args) {
ObjectOutputStream oos = null;
try {
// 创建连接到指定文件的对象输出流实例
oos = new ObjectOutputStream(new FileOutputStream("D:\IOTest\objectSeri.dat"));
oos.write(new Student(101, 22,"张三"));
oos.flush(); //刷新输出流
System.out.println("序列化成功");
} catch ()//异常处理
}
//把指定文件中的数据反序列化回来,并打印输出它的信息
public static void main(String[] args) {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("D:\IOTest\objectSeri.dat"));
Student stu = (Student) ois.readObject();//读取对象
System.out.println(stu);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
ois.close();
}
}
随机存取文件流
RandomAccessFile 是一个特殊的流类,它可以在文件的任何地方读取或写入数据。打开后可以进行只读操作或者读写操作。
在第二个参数指定操作方式: r,rw,rws,rwd.
RandomAccessFile in = new RandomAccessFile("d:\IOTest||music.wmv", "r");
RandomAccessFile inout = new RandomAccessFile("d:\IOTest||music.wmv", "rwd");
类似存在一个文件指针,该文件指针标志将要读写操作的下一个字节的位置, getFilePointer()方法可以返回文件指针的当前位置。seek方法可以将文件指针移动到文件内部的任意字节位置。
随机存取文件流只能操作磁盘文件,不能访问来自网络或内存映像的流。
RandomAccessFile类的多线程下载程序
import java.io.*
import java.net.*
public class MutiThreadDownloadTest{
public static void main(String[] args) thorws IOException{
String urlStr = "http://...sss.mp3" ;//资源地址
URL url = new URL(urlStr); //创建URL
URLConnection con = url.openConnection(); //建立连接
int contentLen = con.getContentLength(); //获取连接资源总长度
int threadQut = 10; //线程数
int subLen = contentLen / threadQut;// 每个线程要下载的大小
int remainder = contenLen % threadQut; // 余数
File destFile = new File("D:\IOTest\sss.mp3"); //目标文件
for (int i = 0; i < threadQut; i++) {
int start = subLen * i; //从目标文件的start位置开始写入到end结束总共subLen个字节
int end = start + subLen - 1;
if (i == threadQut - 1) { //最后一次要加上余数
end += remainder;
}
Thread t = new Thread(new DownloadRunnable(start, end, url, destFile));//开启一个新线程
t.start();//启动新线程
}
}
}
public class DownloadRunnale implements Runnable {
private final int start;
private final int end;
private final URL srcURL;
private final File destFile;
private static final int BUFFER_SIZE = 8192; //缓冲区大小
public DownloadRunnale(int start, int end, URL srcURL, FILE destFile){
this.start = start;
this.end = end;
this.srcURL = srcURL;
this.destFile = destFile;
}
public void run() {
System.out.println("Thread.currentThread().getName()" + "启动");
BufferedInputStream bis = null;
RandomAccessFile ras = null;
byte[] buf = new byte[BUFFER_SIZE];
URLConnection con = null;
try {
con = srcURL.openConnection();
con.setRequestProperty("Range","byte="+start+"-"+end);
bis = new BufferedInputStream(con.getInpputStream());
ras = new RandomAccessFile(destFile,"rw");
ras.seek(start);
int len = -1;
while ((len = bis.read(buf)) != -1) {
ras.write(buf, 0, len);
}
System.out.println(Thread.currentThread().getName() + "下载完毕");
}
}
}