阐述BufferedReader和BufferedWriter的工作原理,
是否缓冲区读写器的性能恒大于非缓冲区读写器的性能,为什么,请举例说明?
答: BufferedReader对Reader类进行了装饰,即在成员变量中声明一个Reader成员变量,在构造时将该成员变量进行初始化,BufferedReader在读取文件时,将读取到的数据存储在字符数组中,下一次读取时,从字符数组中取出对应的数据,避免对物理文件的频繁访问;BufferedWriter对Writer类进行了装饰,在写入数据时,先写入到字符数组中,当字符数组写满时,才将字符数组中的数据清理到物理文件中去。
根据上述工作原理可以看到缓冲区读写器的性能不一定大于非缓冲区读写器的性能。对BufferedReader来说,如果FileReader读取时采用字符数组读取,则会比BufferedReader要快;对BufferedWriter来说,如果一次写入的数据量很大,则FileWriter要快。
写入数据1~1000000数字到文件中,分别使用FileWriter和BufferedWriter实现,考察其效率的不同
package com.kokojia.io;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterBufWriterDemo {
public static void main(String[] args) throws Exception {
/**
* 写入数据1~1000000数字到文件中,分别使用FileWriter和BufferedWriter实现,考察其效率的不同
*/
//非缓冲区字符输出流
FileWriter fw = new FileWriter("f.txt");
long startTime = System.currentTimeMillis();
for(int i=1;i<=1000000;i++) {
fw.write(i+"");
}
System.out.println("FileWriter over!Cost time: "+(System.currentTimeMillis()-startTime));//460
fw.close();
//缓冲区字符输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("f.txt"));
startTime = System.currentTimeMillis();
for(int i=1;i<=1000000;i++) {
bw.write(i+"");
}
System.out.println("BufWriter over!Cost time: "+(System.currentTimeMillis()-startTime));//264
bw.close();
}
}
文件切割:
把较大的文件切割成20k一个的小文件
/**
* 文件切割:把较大的文件切割成size大小的小文件
* @param srcFile
* @param size
* @throws Exception
*/
private static void fileSplit(String srcFile,int size) throws Exception {
FileInputStream fis = new FileInputStream(srcFile);
//获取源文件名
String fileName = srcFile.substring(srcFile.indexOf("/")+1,srcFile.indexOf("."));
//获取源文件后缀名
String sufName = srcFile.substring(srcFile.indexOf(".")+1);
//获得源文件大小
int srcFileSize = fis.available();
//计算切割的数量
int nCount = srcFileSize/size+1;
FileOutputStream fos = null;
byte[] buf = null;
int len = -1;
for(int i=1;i<=nCount;i++) {
fos = new FileOutputStream(srcFile.substring(0,srcFile.indexOf("/")+1)+fileName+"-"+i+"."+sufName);
if(i==nCount) {
int bufLength =srcFileSize-size*(nCount-1);
buf = new byte[bufLength];
fis.read(buf);
fos.write(buf);
}
else {
int bufLength = size;
buf = new byte[bufLength];
fis.read(buf);
fos.write(buf);
}
fos.close();
}
fis.close();
}
文件合成:
把小文件合并成大文件
/**
* 文件合成,把小文件合成大文件
* @param srcFiles
* @param string
* @throws Exception
*/
private static void fileCombine(String[] srcFiles, String destFile) throws Exception {
FileOutputStream fos = new FileOutputStream(destFile);
FileInputStream fis = null;
for(String s: srcFiles) {
fis = new FileInputStream(s);
int len = -1;
byte[] buf = new byte[1024];
while((len=fis.read(buf))!=-1) {
fos.write(buf,0,len);
}
fis.close();
}
fos.close();
}
文件归档解档:
0=txt,1=jpg,2=avi,3=gif
解档归档工具类
package com.kokojia.io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
public class Archive {
/**
* 新建归档文件
* @param srcFiles
* @param destFile
* @throws Exception
*/
public void newArchiver(String[] srcFiles, String destFile) throws Exception {
FileOutputStream fos = new FileOutputStream(destFile);
for(String srcFile: srcFiles) {
addNewFile(srcFile,fos);
}
fos.close();
}
private void addNewFile(String srcFile, FileOutputStream fos) throws Exception {
FileInputStream fis = new FileInputStream(srcFile);
//获取文件后缀名
String sufName = srcFile.substring(srcFile.lastIndexOf(".")+1);
//写入文件后缀名
if(sufName.equals("txt")) {
fos.write((byte)0);
}
if(sufName.equals("mkv")){
fos.write((byte)1);
}
if(sufName.equals("jpg")){
fos.write((byte)2);
}
//获取文件大小,写入文件大小
int fileLength = fis.available();
byte[] fileSizes = int2bytes(fileLength);
fos.write(fileSizes);
//写入文件内容
int len = -1;
byte[] buf = new byte[1024];
while((len=fis.read(buf))!=-1) {
fos.write(buf,0,len);
}
fis.close();
}
/**
* int转化为字节数组
*/
private byte[] int2bytes(int fileLength) {
byte[] fileSizes = new byte[4];
fileSizes[0] = (byte)fileLength;
fileSizes[1] = (byte)(fileLength>>8);
fileSizes[2] = (byte)(fileLength>>16);
fileSizes[3] = (byte)(fileLength>>24);
return fileSizes;
}
/**
* 文件解档
* @param string
* @param string2
* @throws Exception
*/
public void unArchiver(String yarPath, String destPath) throws Exception {
FileInputStream fis = new FileInputStream(yarPath);
byte bytes[] = new byte[1];
int len = -1;
int fileNo = 1;//记数文件个数
String sufNames[] = new String[] {"txt","mkv","jpg"} ;
while((len=fis.read(bytes))!=-1) {
//获取文件大小
byte fileSize[] = new byte[4];
fis.read(fileSize);
int fileLength = bytes2int(fileSize);
//获取文件后缀名
String sufName = sufNames[bytes[0]];
//创建输出文件
FileOutputStream fos = new FileOutputStream(destPath+"/"+fileNo+"."+sufName);
byte buf[] = new byte[1024];
//计算读取次数
int nCount = fileLength/buf.length+1;
for(int i = 1; i<=nCount;i++) {
if(i==nCount) {
byte buf2[] = new byte[fileLength-buf.length*(nCount-1)];
fis.read(buf2);
fos.write(buf2);
}
else {
fis.read(buf);
fos.write(buf);
}
}
fileNo++;
fos.close();
}
fis.close();
}
/**
* byte数组转化为int
*/
private int bytes2int(byte[] fileSize) {
int fileLength = 0;
fileLength = (fileSize[0] & 0xff) | (fileSize[1] & 0xff)<<8 | (fileSize[2] & 0xff)<<16 | (fileSize[3] & 0xff)<<24;
return fileLength;
}
}
测试类
public class ArchiveDemo {
@Test
public void ArchiverTest() throws Exception {
Archive archive = new Archive();
String[] srcFiles = new String[] {"1.txt","2.2 logistic 回归.mkv","test.jpg"};
archive.newArchiver(srcFiles,"all.yar");
System.out.println("over");
}
@Test
public void unArchiverTest() throws Exception {
Archive archive = new Archive();
archive.unArchiver("all.yar","1");
}
}
阐述HashSet与HashMap的异同。
答:HashSet的本质是HashMap,其value项为一个占位符(垃圾变量)。添加元素时,通过key的hash值确定其理应添加的数组位置。依次与当前数组中的元素进行对比,比对原则有三个:(hashcode1hashcode2) && ( o1o2 || (o1.equals(o2)) ),如果没有元素与之相同,则添加到该区间元素的末尾。通过key查询时,先得到key对应的hashcode, 然后定位到所在区间,简化了查询,最后按照上述的三个原则进行比对
Charset类操作: isSupport()
3.1) 通过该类验证平台是否支持以下字符集:
gb2312
GB2312
gbk
GBK
utf-8
utf8
iso8859-1
iso-8859-1
3.2) 取出平台默认的字符集
System.out.println("默认字符集:"+Charset.defaultCharset());
System.out.println("是否支持gb2312: "+Charset.isSupported("gb2312"));
System.out.println("是否支持GB2312: "+Charset.isSupported("GB2312"));
System.out.println("是否支持gbk: "+Charset.isSupported("gbk"));
System.out.println("是否支持GBK: "+Charset.isSupported("GBK"));
System.out.println("是否支持utf-8: "+Charset.isSupported("utf-8"));
System.out.println("是否支持utf8: "+Charset.isSupported("utf8"));
System.out.println("是否支持iso8859-1: "+Charset.isSupported("iso8859-1"));
使用FileInputStream + FileOutputStream / BufferedInputStream + BufferedOuputStream
实现大文件复制,比较复制效率。
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
public class CopyBigFile {
/**
* 使用FileInputStream + FileOutputStream / BufferedInputStream + BufferedOuputStream
实现大文件复制,比较复制效率。
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("1.txt");
for(int i = 0;i<1024*1024;i++) {
fw.write(i+",");
}
fw.close();
//非缓冲区字节输入流
FileInputStream fis=new FileInputStream("test.jpg");
//缓冲区字节输入流
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("test.jpg"));
//非缓冲区字节输出流
FileOutputStream fos=new FileOutputStream("FileOutput.jpg");
//缓冲区字节输入流
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("BufOutput.jpg"));
int len=-1;
byte bytes[] = new byte[1024];
//非缓冲区复制文件
long startTime = System.currentTimeMillis();
while((len=fis.read(bytes))!=-1) {
fos.write(bytes, 0, len);
}
fis.close();
fos.close();
System.out.println("非缓冲区复制完成!耗时:"+(System.currentTimeMillis()-startTime));
//缓冲区复制文件
startTime = System.currentTimeMillis();
while((len=bis.read(bytes))!=-1) {
bos.write(bytes, 0, len);
}
bis.close();
bos.close();
System.out.println("缓冲区复制完成!耗时:"+(System.currentTimeMillis()-startTime));
System.out.println(System.lineSeparator());
System.out.println("over");
}
}
阐述对象回收的前提条件。
答:当内存中没有一个引用可以指向该对象时,该对象将会被回收。在Set集合中,添加对象后,如果将对象的引用置空,对象也不会被回收,因为Set集合中仍然存在该对象的引用。