碰到难题,有个二进制文件,他实际是许多小文件的组合,其存储结构如下,
文件头: 长度32 想把它读到char[]里 它的编码方式不是Unicode
列表长度: 长度32 想把它读到int里 假设他是3 就会有3个列表文件名列表文件名1: 长度128 想把它读到char[]里 它的编码方式不是Unicode
列表文件地址1: 长度32 想把它读到int里
列表文件长度1: 长度32 想把它读到int里列表文件名2: 长度128 想把它读到char[]里 它的编码方式不是Unicode
列表文件地址2: 长度32 想把它读到int里
列表文件长度2: 长度32 想把它读到int里列表文件名3: 长度128 想把它读到char[]里 它的编码方式不是Unicode
列表文件地址3: 长度32 想把它读到int里
列表文件长度3: 长度32 想把它读到int里...
剩下的文件的主体,存放的是各个文件的数据,从这些数据里通过列表文件的地址和长度取出小文件。我的目的就是想读取这种文件的数据,能够将小文件读出来,并且在必要的时候能够写入(例如添加一个小文件,这是需要列表长度+1,而且在列表处添加文件的信息,并将文件的数据写入到文件主体)我以前是Delphi的程序员,学Java已经一个多月了,但是用Java读写文件还是似懂非懂,请哪位指点一下,给出所要用的类有哪些和操作的关键代码就行,谢谢。
文件头: 长度32 想把它读到char[]里 它的编码方式不是Unicode
列表长度: 长度32 想把它读到int里 假设他是3 就会有3个列表文件名列表文件名1: 长度128 想把它读到char[]里 它的编码方式不是Unicode
列表文件地址1: 长度32 想把它读到int里
列表文件长度1: 长度32 想把它读到int里列表文件名2: 长度128 想把它读到char[]里 它的编码方式不是Unicode
列表文件地址2: 长度32 想把它读到int里
列表文件长度2: 长度32 想把它读到int里列表文件名3: 长度128 想把它读到char[]里 它的编码方式不是Unicode
列表文件地址3: 长度32 想把它读到int里
列表文件长度3: 长度32 想把它读到int里...
剩下的文件的主体,存放的是各个文件的数据,从这些数据里通过列表文件的地址和长度取出小文件。我的目的就是想读取这种文件的数据,能够将小文件读出来,并且在必要的时候能够写入(例如添加一个小文件,这是需要列表长度+1,而且在列表处添加文件的信息,并将文件的数据写入到文件主体)我以前是Delphi的程序员,学Java已经一个多月了,但是用Java读写文件还是似懂非懂,请哪位指点一下,给出所要用的类有哪些和操作的关键代码就行,谢谢。
BufferedReader in = new BufferedReader(new FileReader("infilename"));
String str;
while ((str = in.readLine()) != null) {
process(str);
}
in.close();
} catch (IOException e) {
}逻辑方面,还是自己写吧。
InputStream is = new FileInputStream(file); long length = file.length(); if (length > Integer.MAX_VALUE) {
// File is too large
} byte[] bytes = new byte[(int)length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file "+file.getName());
}
is.close();
return bytes;
}
FileInputStream in = new FileInputStream(new File("infilename"));
int str;
while ((str = in.read()) !=-1) {
process(str);
}
in.close();
} catch (IOException e) {
}
就是读文件啊文件头: 长度32 想把它读到char[]里 它的编码方式不是Unicode
列表长度: 长度32 想把它读到int里 假设他是3 就会有3个列表文件名先不关编码,长度32 你就把前32读了 byte【32】
在接着读32为啊 然后转为int看是几
然后
文件的结构你知道就没问题啊
import java.io.*;class SmallFile {
static final int HEADLEN = 24; //头总长度
byte[] fileName = new byte[16]; //列表文件名1: 长度128 想把它读到char[]里 它的编码方式不是Unicode。在不确定编码方式的时候,最好直接用byte[]来存放
int offset; //列表文件地址1: 长度32 想把它读到int里
int length = -1; //列表文件长度1: 长度32 想把它读到int里
byte[] content;
public SmallFile() { } public SmallFile(byte[] fn, byte[] content) {
Arrays.fill(fileName, (byte) 0);
if (fn != null) {
if (fn.length <= 16) {
System.arraycopy(fn, 0, fileName, 0, fn.length);
}
else {
System.arraycopy(fn, 0, fileName, 0, 16);
}
}
this.content = content;
if (content != null) {
this.length = content.length;
}
else {
this.length = -1;
}
}
}public class ReadBinary {
static final int HEADLEN = 8; //头总长度
private String filename;
private byte[] filehead = new byte[4]; //文件头: 长度32 想把它读到char[]里 它的编码方式不是Unicode
private int filecount = -1; //列表长度: 长度32 想把它读到int里 假设他是3 就会有3个列表文件名
private List<SmallFile> files = null; public void setFilehead(byte[] fh) {
if (fh == null)
return;
Arrays.fill(filehead, (byte) 0);
if (fh.length <= 4) {
System.arraycopy(fh, 0, filehead, 0, fh.length);
}
else {
System.arraycopy(fh, 0, filehead, 0, 4);
}
} public ReadBinary(String filename) {
try {
readFromFile(filename);
}
catch (Exception ex) {
System.out.println(ex.getMessage());
System.out.println("在载入数据文件时失败,因此视同为新建一个数据文件!");
this.filename = filename;
Arrays.fill(filehead, (byte) 0);
filecount = 0;
files = new ArrayList<SmallFile> ();
}
} public void readFromFile(String filename) throws Exception {
BufferedInputStream bin = new BufferedInputStream(new FileInputStream(
filename));
this.filename = filename;
DataInputStream in = new DataInputStream(bin);
in.read(filehead); //文件头: 长度32 想把它读到char[]里 它的编码方式不是Unicode
filecount = in.readInt(); //列表长度: 长度32 想把它读到int里 假设他是3 就会有3个列表文件名
if (files == null) {
files = new ArrayList<SmallFile> ();
}
else {
files.clear();
}
for (int i = 0; i < filecount; i++) {
SmallFile file = new SmallFile();
in.read(file.fileName);
file.offset = in.readInt(); //列表文件地址1: 长度32 想把它读到int里
file.length = in.readInt(); //列表文件长度1: 长度32 想把它读到int里
files.add(file);
}
} public void writeToFile() throws Exception {
String temp = filename + ".tmp"; //临时文件
boolean exists = false;
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile(filename, "r"); //文件存在则从文件读入
exists = true;
}
catch (Exception ex) {
System.out.println("文件不存在,因此启用内存写入模式");
}
if (filecount != files.size()) {
throw new Exception("怪事,居然不相同??");
}
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new
FileOutputStream(temp)));
//1、写总文件头
out.write(filehead);
out.writeInt(filecount);
//2、写列表头
int sumlength = 0;
for (int i = 0; i < files.size(); i++) {
SmallFile file = files.get(i);
out.write(file.fileName);
if (file.length < 0) {
throw new Exception("怪事,文件长度怎么可能小于0?");
}
else {
out.writeInt(ReadBinary.HEADLEN + SmallFile.HEADLEN * filecount +
sumlength);
sumlength += file.length;
out.writeInt(file.length);
}
}
//3、写文件内容
for (int i = 0; i < files.size(); i++) {
SmallFile file = files.get(i);
if (file.content != null && (file.length == file.content.length)) {
out.write(file.content);
}
else if (exists) {
raf.seek(file.offset);
byte[] b = new byte[file.length];
raf.read(b);
System.out.println("b:" + new String(b));
out.write(b);
}
else {
throw new Exception("怪事,又不能从内存读,又不能从文件读。这活没法干了!");
}
} out.close();
if (raf != null) {
raf.close();
raf = null;
}
System.gc();
//把原先的文件删除
File f = new File(filename);
f.delete();
//再把临时文件改名到正式文件
File f2 = new File(temp);
f2.renameTo(f);
} public void addFile(SmallFile file) {
if (files != null) {
filecount++;
files.add(file);
}
}
public static void test1(){
ReadBinary rb = new ReadBinary("f:\\temp\\rb.dat");
rb.setFilehead("HEAD1234567890122222222222222222".getBytes());
SmallFile f = new SmallFile("第1个文件".getBytes(), "第1个文件的内容".getBytes());
rb.addFile(f);
try {
rb.writeToFile();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
public static void test2(){
ReadBinary rb = new ReadBinary("f:\\temp\\rb.dat");
rb.setFilehead("HEA".getBytes());
SmallFile f = new SmallFile("第2个文件".getBytes(), "第2个文件的内容".getBytes());
rb.addFile(f);
try {
rb.writeToFile();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
//test1();
test2();
}
}
//package com.ricky.www
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.ByteBuffer;public class Test{
public static void main(String[] args)throws IOException{
/**
*这里假设要将Total.bin的前10个字节写入ricky.bin
*将后12个字节写入jennie.bin
*/
separate();
} private static void separate()throws IOException{
File total = new File("Total.bin");
File ricky = new File("ricky.bin");
File jennie = new File("jennie.bin"); FileInputStream fis = new FileInputStream(total);
FileOutputStream fos1 = new FileOutputStream(ricky);
FileOutputStream fos2 = new FileOutputStream(jennie);
FileChannel tChannel = fis.getChannel();
FileChannel rChannel = fos1.getChannel();
FileChannel jChannel = fos2.getChannel(); ByteBuffer buffer1 = ByteBuffer.allocate(10); //这里指定缓冲区大小
ByteBuffer buffer2 = ByteBuffer.allocate(12); tChannel.read(buffer1);
tChannel.read(buffer2); buffer1.flip();
buffer2.flip(); rChannel.write(buffer1);
jChannel.write(buffer2); fis.close();
fos1.close();
fos2.close();
}
}
想要写的话, 要用到 RandomAccessFile添加新文件的方法:
如果里面有三个小文件,你想写第四个小文件。因为都是顺序写入,头没有剩余空间。那你可以先把第一个小文件读出来写到文件尾,然后更新第一个文件的地址,就可以把小文件原来的空间当作头来写了。写完之后,再更新头所表示的小文件数目。(为了安全性,写的顺序有一定讲究)以下是读的实例代码:public class CustomFile { public CustomFile(File file) throws FileNotFoundException, IOException {
DataInputStream in = null;
try {
in = new DataInputStream(new FileInputStream(file)); head = new char[]{in.readChar(), in.readChar()}; infos = new FileInfo[in.readInt()];
for (int i = 0; i < infos.length; i++) {
infos[i] = new FileInfo(file, in);
}
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ex) {
Logger.getLogger(CustomFile.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public char[] head;
public FileInfo[] infos; public static class FileInfo { private FileInfo(File file, DataInputStream in) throws IOException {
this.file = file;
name = new char[8];
for (int i = 0; i < name.length; i++) {
name[i] = in.readChar();
}
address = in.readInt();
length = in.readInt();
} public InputStream getInputStream() throws IOException {
InputStream in = new FileInputStream(file);
in.skip(address);
return new _InputStream(in, length);
}
private File file;
public char[] name;
public int address;
public int length;
} private static class _InputStream extends InputStream { public _InputStream(InputStream in, int length) {
this.in = in;
this.length = length;
} @Override
public int read() throws IOException {
if (length <= 0) {
return -1;
} else {
length--;
return in.read();
}
} @Override
public void close() throws IOException {
in.close();
}
private InputStream in;
private int length;
}
}
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DiskTest {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
File file = new File("D:\\picture.rar");
byte[] content=readFile(file);
System.out.println(content);
writeBytes("D:\\picture1.rar",content);
} /** *//**读文件到字节数组
* @param file
* @return
* @throws Exception
*/
static byte[] readFile(File file) throws Exception {
if (file.exists() && file.isFile()) {
long fileLength = file.length();
if (fileLength > 0L) {
BufferedInputStream fis = new BufferedInputStream(
new FileInputStream(file));
byte[] b = new byte[(int) fileLength];
while (fis.read(b)!= -1) {
}
fis.close();
fis = null; return b;
}
} else {
return null;
}
return null;
} /** *//**将字节数组写入文件
* @param filePath
* @param content
* @return
* @throws IOException
*/
static boolean writeBytes(String filePath, byte[] content)
throws IOException {
File file = new File(filePath);
synchronized (file) {
BufferedOutputStream fos = new BufferedOutputStream(
new FileOutputStream(filePath));
fos.write(content);
fos.flush();
fos.close();
}
return true; }
}