我必须使用Java读取旧格式的二进制文件.
简而言之,该文件有一个标题,由几个整数,字节和固定长度的char数组组成,后跟一个记录列表,它们也包含整数和字符.
在任何其他语言中,我将创建structs(C/C++)或records(Pascal/Delphi),它们是标题和记录的逐字节表示.然后我将sizeof(header)字节读入标头变量并对记录执行相同操作.
像这样:(Delphi)
type
THeader = record
Version: Integer;
Type: Byte;
BeginOfData: Integer;
ID: array[0..15] of Char;
end;
...
procedure ReadData(S: TStream);
var
Header: THeader;
begin
S.ReadBuffer(Header, SizeOf(THeader));
...
end;
Run Code Online (Sandbox Code Playgroud)
用Java做类似事情的最佳方法是什么?我是否必须自己阅读每一个值,还是有其他方法来做这种"块读"?
Pow*_*ord 34
据我所知,Java强制您以字节形式读取文件,而不是阻止读取.如果您正在序列化Java对象,那将是一个不同的故事.
显示的其他示例将DataInputStream类与File一起使用,但您也可以使用快捷方式:RandomAccessFile类:
RandomAccessFile in = new RandomAccessFile("filename", "r");
int version = in.readInt();
byte type = in.readByte();
int beginOfData = in.readInt();
byte[] tempId;
in.read(tempId, 0, 16);
String id = new String(tempId);
Run Code Online (Sandbox Code Playgroud)
请注意,您可以将响应对象转换为类,如果这样可以更容易.
Wil*_*ger 20
如果您要使用Preon,那么您所要做的就是:
public class Header {
@BoundNumber int version;
@BoundNumber byte type;
@BoundNumber int beginOfData;
@BoundString(size="15") String id;
}
Run Code Online (Sandbox Code Playgroud)
完成后,您可以使用一行创建Codec:
Codec<Header> codec = Codecs.create(Header.class);
Run Code Online (Sandbox Code Playgroud)
你像这样使用Codec:
Header header = Codecs.decode(codec, file);
Run Code Online (Sandbox Code Playgroud)
Vin*_*nie 19
您可以使用DataInputStream类,如下所示:
DataInputStream in = new DataInputStream(new BufferedInputStream(
new FileInputStream("filename")));
int x = in.readInt();
double y = in.readDouble();
etc.
Run Code Online (Sandbox Code Playgroud)
获得这些价值后,您可以随意使用它们.在API中查找java.io.DataInputStream类以获取更多信息.
Joe*_*eda 10
我可能误解了你,但在我看来,你正在创建内存结构,你希望每个字节的字节精确表示你想要从硬盘读取的内容,然后将整个内容复制到内存和操纵那个?
如果确实如此,那你就玩了一场非常危险的比赛.至少在C中,标准不强制执行诸如填充或对齐结构成员之类的事情.更不用说像大/小字节序或奇偶校验位......所以即使你的代码碰巧运行它是非常不可移植和冒险的 - 你依赖编译器的创建者不会改变它对未来版本的想法.
最好创建一个自动机,以验证从HD读取的结构(每字节字节数)是否有效,并填写内存结构(如果确实可以).尽管你获得了平台和编译器的独立性,但你可能会失去一些毫秒(不像现代操作系统看起来那样做很多磁盘读缓存).此外,您的代码将轻松移植到另一种语言.
帖子编辑:在某种程度上我同情你.在DOS/Win3.11的好日子里,我曾经创建了一个C程序来读取BMP文件.并使用完全相同的技术.一切都很好,直到我尝试为Windows编译它 - 哎呀!Int现在是32位长,而不是16位!当我尝试在Linux上编译时,发现gcc的位字段分配规则与Microsoft C(6.0!)完全不同.我不得不求助于宏观技巧让它变得便携......
小智 7
我使用了Javolution和javastruct,它们都处理字节和对象之间的转换.
Javolution提供了表示C类型的类.您需要做的就是编写一个描述C结构的类.例如,从C头文件,
struct Date {
unsigned short year;
unsigned byte month;
unsigned byte day;
};
Run Code Online (Sandbox Code Playgroud)
应该翻译成:
public static class Date extends Struct {
public final Unsigned16 year = new Unsigned16();
public final Unsigned8 month = new Unsigned8();
public final Unsigned8 day = new Unsigned8();
}
Run Code Online (Sandbox Code Playgroud)
然后调用setByteBuffer初始化对象:
Date date = new Date();
date.setByteBuffer(ByteBuffer.wrap(bytes), 0);
Run Code Online (Sandbox Code Playgroud)
javastruct使用注释来定义C结构中的字段.
@StructClass
public class Foo{
@StructField(order = 0)
public byte b;
@StructField(order = 1)
public int i;
}
Run Code Online (Sandbox Code Playgroud)
要初始化对象:
Foo f2 = new Foo();
JavaStruct.unpack(f2, b);
Run Code Online (Sandbox Code Playgroud)