質問: C#からAndroid上の自作DLL経由でファイル内のある部分のバイナリーデータを取得するサンプルを作っています。 下記ソースのfpはファイルポインタになっていて、ファイルの中身は10個のファイルのバイナリーが敷き詰められています。 **■質問** ファイル内のファイル5のデータとファイル6のデータの間にNULLがなかった場合、 ファイルのオフセット位置をファイル5にしてファイルポインタを返すと オフセット位置以降のすべてのバイナリーがC#側に返るのでしょうか? 現在テストしているとすごい数のバイト配列になっているので、 ファイルの末端までのバイト配列が返っているのではないかと思っています。 オフセット位置を指定して次のデータまでのバイト配列を返してもらうには データ間にNULLがあれば良いのか、改行コードをいれるのか、 サイズ指定してmemcpyしたバッファを返せば良いのか 調べているのですが答えにたどり着けません。 **●C#** ``` [DllImport ("ReadFile")] private static extern byte[] GetFileMemory(int offset); ``` **●C++** ``` extern "C"{ const char** GetFileMemory(int offset); } const char** GetFileMemory(int offset) { fseek(fp, offset, SEEK_SET); return (const char**)fp; } ```
回答: まず、 `fopen()` した時点では**ファイルの中身は読み込んでいません**。実際にデータを読み取るためには、自分で確保したバッファを `fread()` 等に渡します。これを必要なサイズ or EOF に到達するまで繰り返すことになります。このあたりはまず C 言語等の資料を参考にしてください。 次に C# 側にマーシャリングするわけですが、C#側で管理される `byte[]` 型にする以上、その**配列全体をマネージヒープ上にコピー**しなければなりません。となるとサイズの情報が必要になりますが、C言語のポインタにはそんなものありませんから、 * (確認していませんが)`MarshalAsAttribute.SizeConst` でサイズを指定しておく * `IntPtr` で受け取って `Marshal.Copy` する * C#側から `byte[]` を渡して、そこにC側でセットしてもらう などのアプローチをとる必要があります。 参考 * 配列に対する既定のマーシャリング.aspx) * c# - Can IntPtr be cast into a byte array without doing a Marshal.Copy? - Stack Overflow なお、質問に提示された宣言でどのようなマーシャリングが行われたのか定かではありませんが、ヌル終端の文字列もしくは SafeArray として扱われたのかなと考えています。 > > Heap領域が1度膨れ上がるとアプリを落とすまで解放されないので、C++側(ネイティブ側)でリソースファイルを管理しC#側のHeapに載らないようにしてます。 > > > 今回の場合、いずれにせよ `byte[]` がマネージヒープに載るわけですし、 `Stream` クラスを使えば C# でもファイルの一部分だけを読み取ることができますが、それでも甲斐はあるのでしょうか?