MyOD
一、设计思路
确定MyOD的要求
根据需求可知MyOD需要实现类似Linux下
od -tx -tc XXX的功能,于是先去网上查找了一下od命令的-tx
以及-tc
参数的作用,经查找后了解到命令参数的功能如下。
- 最左侧用7位8进制数显示当前字节的数目,从
0000000
开始,每输出16个字节或字节序列结束时输出一次该7位数字。 - 将从文件中读入的字节转化为二位十六进制数并按特定的顺序分为四个一组进行输出,当一组中数目不足时不足的部分用0补上。
- 在十六进制数的下一行输出字节的ASCII值。
(一)将命令行中的参数传入MyOD
使用args[]数组将命令行中输入的文件名参数记录下来,在本程序中文件名存放在args[2]中。
(二)定义输入输出流,对文件进行操作
在MyOD中我使用了字节输入输出流。在创建字节输入输出流对象后通过使用read(byte b[])
方法将文件中的字节读入到字节数组input中,并返回读入的字节长度到变量length
中。输入输出流一定要在try-catch语句中运行,字节流也需要在使用之后关闭流。
(三)将读入的字节数据转化为二位十六进制数
在这里我使用了for
循环语句,并使用变量length控制次数,且在这一过程中将不足二位的十六进制数转化为十六进制数。进制转化的过程中我使用了Integer类的toHexString(byte b)
方法减少了转化的难度。相关代码如下
for (i = 0; i < length; i++) {
temp = Integer.toHexString(input[i]);//转化为二位十六进制数
if (temp.length() != 2) {//如果不足二位
temp = "0" + temp;
if (temp.length() != 2) {
temp = "0" + temp;
}
}
numsix[i] = temp;
}
(三)将读入的数据分为有需要加0的组和不需要加0的组,依此来设置十六进制数输出的实际长度
由于这两种情况的区别仅仅是实际输出的长度,于是我将后续的输出语句写在了output()
方法中
(三)输出每行的当前字符数以及按组输出二位十六进制数以及字节相应的ASCII值
我将这些功能都放入了output
方法中,需要注意的是每组输出的数据的顺序与本来的顺序相反,读入的换行符也需要输出。由于该部分内容较多,我把相关思路写在代码注释中了。
public static void output(byte[] input,String[] numsix,int length,int temlength){//读入的字节放在input中,numsix中放转换后的二位十六进制数,length为读入字节数,temlength为实际输出的二位十六进制数的个数
int i, j, k;
String[] str = new String[temlength];//存放temlength长度的实际输出的二位十六进制数
for (i = 0; i < length; i++) {
str[i] = numsix[i];
}
for (i = length; i < temlength; i++) {
str[i] = "00";
}
for (i = 0; i < temlength; i++) {//输出7位当前字节数目,从`0000000`开始,每输出16个字节或字节序列结束时输出一次该7位数字。
if (0 == (i % 16) || (temlength - 1) == i) {
if ((temlength - 1) == i) {
System.out.printf("
%07o", length);
} else if (0 == i) {
System.out.printf("
%07o", 0);
} else if (0 == i % 16) {
System.out.printf("
%07o", i);
} else {
System.out.println(i);
System.out.printf("
%07o", i + 1);
}
}
if (0 == i % 4) {//每组要按反序输出
System.out.print(" ");
for (j = i + 3; j >= i; j--) {
System.out.print(str[j]);
}
}
if (i < length) {//每行有16个字节或到最后一个字节时换行,并输出上一行数据对应的ASCII
if (0 == ((i + 1) % 16) || (temlength - 1) == (i + 1)) {
System.out.println();
System.out.print(" ");
if (0 == ((i + 1) % 16)) {
for (k = i - 15; k <= i; k++) {
if ((char) input[k] == '
') {//当ASCII值是换行符时另外输出
System.out.print("\n");
} else {
System.out.printf("%c", (char) input[k]);//转化为ASCII
}
System.out.print(" ");
}
} else if ((temlength - 1) == (i + 1)) {
for (k = i - (length % 16)+2 ; k <= i+1; k++) {
if ((char) input[k] == '
') {
System.out.print("\n");
} else {
System.out.printf("%c", (char) input[k]);
}
System.out.print(" ");
}
}
}
}
}
}
二、测试代码
由于需要使用命令行传入参数,因此没有使用junit对代码进行测试,运行结果及遇到的相关问题请见后面部分。
三、运行结果
四、码云代码
五、遇到的问题
该程序较为困难的地方在于如何控制分组并在合适的地方进行换行输出,在实现这一过程中遇到了许多问题,我就没有逐个例举了。
- 问题1:输出的7位数字不符合预期,更改变量后仍不正确。
- 问题1解决方法:后面想到该7位数字是八进制的,需要对个数进行进制的转换。
- 问题2:在对数据进行格式转换时出现java.lang.NumberFormatException 错误。
- 问题2解决方法:找到相应的进行转化的代码,发现是读入了空格,于是使用
trim()
方法去除两端的空格,该错误的详细解决方法请见参考资料。 - 问题3:输出的ASCII值自动换行。
- 问题3解决方法:输出了换行符,对换行符进行另外的输出。
六、感想与思考
本次选做需要实现的MyOD类还是比较困难的,需要解决的问题很多,尤其是在控制分组并在合适的地方进行换行输出,并在换行后如何输出ASCII值,由于这次不太方便使用IDEA,没法进行调试,这给编程的过程造成了比较大的困难,但这也使我能对命令行中返回的错误有所了解。