可能大家曾经碰到过,有一些软件它的数据是一种独有的格式,比如酷狗音乐的歌词文件是KRC格式,漫画魔屏的漫画文件是MOSC格式的,你不能用一般的软件去打开它。这是一种只有它软件本身能够读写的文件,这样就能做到很好的保密效果。
虽然我不能办到从上述的文件中提取我想要的东西出来,但是我根据我对这种做法的理解,我已经能够做到,让自己的软件读写自己独有的格式。
一、原理。
原理很简单,这个得从计算机的基本概念开始说起。文件在计算机中的存储形式是二进制编码,常见的字符(标准英文字母和数字、英文符号)每一种在计算机中都有一个对应的二进制编码表示,即是ASCII码。例如数字1的ASCII码是49,而数字1在计算机中的存储表示为00110001。
文件的基本单位是字节(byte),一个字节用8位二进制表示。因此,我用来生成独特格式的文件方法就是从字节方式来进行文件读写。
二、代码实现。
(1)文件合成:类似于文件压缩,但这里并没有使用压缩算法,只是将几个普通文件合成为一个特殊文件,即这里我所说的独特格式文件。
主要字节存储方式按下图结构:
public static String groupFolderPath = "F:\\FSD";
public static String syntheticFilePath = "F:\\new.syn";
public static void synthesizeFiles() {
// 存放需要合成的多个文件的文件夹
File gfpFile = new File(groupFolderPath);
// 扫描文件夹
File[] cfs = gfpFile.listFiles();
File synFile = new File(syntheticFilePath);
try {
if (!synFile.exists()) {
synFile.createNewFile();
}
FileOutputStream fos = new FileOutputStream(synFile);
DataOutputStream dos = new DataOutputStream(fos);
dos.writeInt(cfs.length);
dos.writeByte((byte) ' ');
// 文件名存放
String[] fns = new String[cfs.length];
// 文件大小存放
int[] fbtls = new int[cfs.length];
// 文件字节
byte[][] fbts = new byte[cfs.length][];
for (int i = 0; i < cfs.length; i++) {
fns[i] = cfs[i].getName();
fbts[i] = getFileBytes(cfs[i]);
fbtls[i] = fbts[i].length;
}
for (int j = 0; j < fns.length; j++) {
// 以UTF-8编码写入字符串
dos.writeUTF(fns[j]);
dos.writeByte((byte) ',');
dos.writeInt(fbtls[j]);
dos.writeByte((byte) ' ');
}
for (int k = 0; k < fbts.length; k++) {
dos.write(fbts[k]);
}
System.out.println("文件合成成功,合成文件地址:" + syntheticFilePath);
dos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获得文件的字节码,以字节数组存储
*
* @param file
* 需要的读取文件
* @return bytes
* @throws IOException
*/
public static byte[] getFileBytes(File file) throws IOException {
byte[] bytes = null;
FileInputStream fis = new FileInputStream(file);
DataInputStream dis = new DataInputStream(fis);
int le = dis.available();
bytes = new byte[le];
dis.read(bytes);
dis.close();
fis.close();
return bytes;
}
(2)文件分解:类似于压缩文件解压,根据上述文件写入格式,读取相应位置数据,生成“解压”文件。
public static String decomposedFolderPath = "F:\\Decomposed";
public static void decomposeFile() {
File synFile = new File(syntheticFilePath);
try {
FileInputStream fis = new FileInputStream(synFile);
DataInputStream dis = new DataInputStream(fis);
// 读取文件个数
int fileNum = dis.readInt();
// 读取空格字符,并将光标向后移动
dis.readByte();
// 文件名存储
String[] fns = new String[fileNum];
// 文件大小存储
int[] les = new int[fileNum];
for (int i = 0; i < fileNum; i++) {
// 按UTF-8编码读取第i个文件的文件名
fns[i] = dis.readUTF();
// 读取字节,主要目的是将光标后移一字节
dis.readByte();
// 读取第i个文件的文件大小
les[i] = dis.readInt();
dis.readByte();
}
byte[][] bts = new byte[fileNum][];
for (int j = 0; j < fileNum; j++) {
bts[j] = new byte[les[j]];
// 读取第j个文件的字节数据
dis.read(bts[j], 0, les[j]);
}
for (int k = 0; k < fileNum; k++) {
File df = new File(decomposedFolderPath + File.separator
+ fns[k]);
if (!df.exists()) {
File pf = df.getParentFile();
if (!pf.exists()) {
pf.mkdirs();
}
df.createNewFile();
}
System.out.println("分解出文件【文件名:" + fns[k] + " , 大小 : " + les[k]
+ "】");
writeFileBytes(df, bts[k]);
}
dis.close();
fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 向相应空白文件中写入字节数据
*
* @param file
* 文件
* @param bytes
* 需要写入的字节数据
* @throws IOException
*/
public static void writeFileBytes(File file, byte[] bytes)
throws IOException {
FileOutputStream fos = new FileOutputStream(file);
DataOutputStream dos = new DataOutputStream(fos);
dos.write(bytes);
dos.close();
fos.close();
}
三、运行效果图。
需要合成的文件:
生成的特殊格式文件:
分解特殊格式文件生成的文件:
通过以上方法,即可成功生成特殊格式的文件,并且并非不可逆的,也就是说,不是合成了就乱了,还可以原封不动的还原,而且不会丢失数据。当然这只是提供了一种思路,生成自己的独特格式的时候,文件存储具体采用什么格式就看自己的需要了,这样就能让自己的数据的“藏”起来了。除非知道你的存储规律,否则是无法读取你的数据的。
当然,这只能代表我个人的看法,如有雷同,纯属巧合。写得不好,欢迎大家批评指正。