質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.45%
.NET Core

.NET Coreは、マネージソフトウェアフレームワークでオープンソースで実装されています。クロスプラットフォームを前提に考えられており、Windows/Mac/Linuxで動くアプリケーションを作成することが可能です。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Mono

Monoは、Ecma標準に準じた.NET Framework互換の環境を実現するためのオープンソースのソフトウェア群です。Linux、Mac OS X、Windowsなど多くのプラットフォームで動作します。その他にも、特定プラットフォーム向けに特化したサブプロジェクトも存在します。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

Q&A

解決済

3回答

7376閲覧

Unityで2GBを超える配列を扱いたい

ta93san

総合スコア23

.NET Core

.NET Coreは、マネージソフトウェアフレームワークでオープンソースで実装されています。クロスプラットフォームを前提に考えられており、Windows/Mac/Linuxで動くアプリケーションを作成することが可能です。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Mono

Monoは、Ecma標準に準じた.NET Framework互換の環境を実現するためのオープンソースのソフトウェア群です。Linux、Mac OS X、Windowsなど多くのプラットフォームで動作します。その他にも、特定プラットフォーム向けに特化したサブプロジェクトも存在します。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

1グッド

3クリップ

投稿2020/03/12 07:32

編集2020/03/12 08:07

やりたいこと

Unityでセーブデータを保存する際にJsonテキストへのシリアライズを行うのが良く使われる方法の一つかと思います。
データをシリアライズした結果のJsonテキストをstreamに書き出そうとしたのですが、
C#の制限で1つの配列が保持できる要素数がint32.MaxValueの半分2147483591個
https://stackoverflow.com/questions/21408786/maximum-number-of-elements-in-an-array-vs-maximum-indexer-value
の制限に引っかかってしまいました。

普通のC#アプリではこの制限を拡張し、2147483591個以上の配列を持てるようにする方法があるようです。
(C#のApp.configに設定を追記するのかな?)

やりたいこととしてはUnityで上記C#での方法を実現したいです。
(UnityではApp.configに対応するものはどこに作られるのでしょうか?)
よろしくお願いいたします。

やってみたこと

シリアライズしたい構造体dataがあって、これはかなり大きなデータを持っています。
System.Runtime.Serialization.Json.DataContractJsonSerializer.WriteObject(stream, data)
の部分でdataのシリアライズ結果の文字列をstreamに書き出しています。ここでシリアライズ結果の文字数が2147483591個を超えると、stream内のバイト配列の要素数が上限を超えるためエラーが起きます。

C#

1 using(System.IO.MemoryStream stream = new System.IO.MemoryStream()) 2 using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write)) 3 { 4 System.Runtime.Serialization.Json.DataContractJsonSerializer serializer 5 = new System.Runtime.Serialization.Json.DataContractJsonSerializer(data.GetType()); 6 serializer.WriteObject(stream, data); 7 } 8
s.k👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hihijiji

2020/03/12 07:58

パッと見た感じ制限が無くても大量の(10GByteとか)空きメモリが無いとまともに動かないコードです。 それで良いのですか?
ta93san

2020/03/12 08:06 編集

コメントいただきありがとうございます。 普通はMemoryStreamではなくFileStreamに書き出すと思います。 実際のソースではこの後Zip圧縮してファイル出力しているので、とりあえずMemoryStreamに書き出しているという次第です。 string text = System.Text.Encoding.UTF8.GetString(stream.ToArray()); の部分は確認用ですので無視してください。(わかりづらいので消しますね。)
miyabi_takatsuk

2020/03/12 15:16

Unity詳しくないので、なんとなくですが、 セーブデータの容量を抑える方がいいのかと・・・。 たとえば、計算式や構造は、アプリケーション側で保持して、 必要な数値とかだけ、セーブデータで保持するとか。 具体的には、セーブデータには主人公らのレベルとか、職業のIDだけを保持し、 ステータスの計算、表示は、アプリケーション起動時にやる、とか。 既にそうしてるのに容量大きかったらすみません・・・。
ta93san

2020/03/12 16:09

コメントいただきありがとうございます。 データの大部分はfloatの配列なので、これ以上小さくはできないと思われます。
miyabi_takatsuk

2020/03/12 17:31

float配列でそのデータ量・・・。 もしかして、ポリゴンの座標とか持っちゃってたりしませんか? とにかく、セーブデータとして保持させるその、float配列の量だったり、数を減らすーとかできないのでしょうか? そのために、ゲーム側で保持させるものを工夫して、必要最低限のデータのみをセーブデータに保持するよう構築する、とか・・・。 いや、Unity使ったことない身でいろいろコメントしてすみません。 具体的に、なんの要素をセーブデータに落とし込んでいるか、を質問に記載すれば、回答つきやすくなるかと思いますよー (セーブデータにすべきでないものもセーブさせている可能性も見つけていけるかも)
ta93san

2020/03/12 23:57

すみません。具体的になぜそれをしたいのか?という部分が抜けていましたね。 座標であることは確かなのですが、解析結果なのでデータとして削れる部分がないのです。 「解析結果」のような大きなデータは構造体として保持せずに別ファイルとして出すのが正解なのでしょうが、解析結果を保持している構造体が階層構造になっていて、解析結果だけ分けるのが難しいため、Jsonでそのまま書き出したかったということです。
hihijiji

2020/03/13 01:13

例えば平均値が欲しい場合には、サンプルデータの数とその平均値さえ記録しておけば、 新たに取得した値と合わせての平均値を出すことは容易です。 他の統計値に関しても同様です。と言うか普通はそうします。
hihijiji

2020/03/13 02:12

Unityだからゲームかと思ったけど、構造を3D的に表示したいとかっぽいですね。 ↑は忘れてください。
miyabi_takatsuk

2020/03/13 02:28

> すみません。具体的になぜそれをしたいのか?という部分が抜けていましたね。 ぜひその事も質問文に加えてください。 きっとそこまで書けば回答を得られると思いますよ。 であれば、Unityで使用できるはずの、マシン内ローカルDBを使うのはいかがでしょうか? 値の配列自体は、ローカルDBに保存し、インクリメントIDで一意のレコードにしておき、セーブデータには、そのIDを保持する、とか。 そうすれば、1万分の1以下のデータ量でいけるかと。 (ここまで書くなら回答で書けって感じでよね、すみません)
guest

回答3

0

ベストアンサー

ここでシリアライズ結果の文字数が2147483591個を超えると、stream内のバイト配列の要素数が上限を超えるためエラーが起きます。

文字列長の問題なのであれば、「gcAllowVeryLargeObjects」の設定では解決しないのではないでしょうか。
公式ドキュメントに以下の記載がありますので、ご参考にしてください。

文字列およびその他の非配列オブジェクトの最大サイズは変更されません。

<gcAllowVeryLargeObjects> 要素 | Microsoft Docs
https://docs.microsoft.com/ja-jp/dotnet/framework/configure-apps/file-schema/runtime/gcallowverylargeobjects-element


そもそもですが、セーブデータの容量が 2GB を超えていることに、「データ設計に何らかの問題があるのではないか?」と疑ってしまいます。
具体的なデータを提示していただいていないので、助言することはできませんが、一度見直しをすることをおすすめします。

その上で、大容量のデータを保存する必要がある場合は、データが肥大化してしまう JSON 形式はやめて、バイナリ形式または小容量のシリアライズ形式(MessagePack や Protocol Buffers など)で保存することをおすすめします。

また、それでも容量が大きすぎる場合は、データを分割して保存してください。

投稿2020/03/13 05:15

nskydiving

総合スコア6500

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ta93san

2020/03/16 10:54

皆様ご回答いただき有難うございます。 結論といたしましては保存したいデータのSerializableにしたラッパークラスを作成してBinaryFormatterを使ってバイナリとして保存することとしました。 あまり大きなデータをjsonで保存しようとしたのがそもそもの間違いということですね。 でかいデータのIOをしたいならIO専用のnativeのdllとかつくってやるのが正解な気がしました。 ガベコを酷使しすぎであると、よい勉強になりました。 ご回答いただいた皆様ありがとうございました。
guest

0

FileStreamも内部的には2GBを上限とするポインタを持っているとおもって調べてみた感じ、エラーは出るみたいです
一応回避方法もかいているので参考にしてみてください
https://cms.shise.net/2014/10/csharp-streamwriter-2gb-exception/

他の人も言ってるように設計がおかしいとか、そもそもC#向きの案件ではないと思います

投稿2020/03/13 09:03

izmktr

総合スコア2856

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takabosoft

2020/03/16 00:11

StreamWriterとFileStreamは別物では?
KOZ6.0

2020/03/16 13:30

提示された URL のエラーになるというコードを実行してみましたが、2G 越えても大丈夫ですね。 2014年と、少々古い記事ですし、エラー内容を見ると Encoder まわりに不具合があって修正が入ったのかもしれません。
guest

0

環境が無いので試せませんが、MemoryStreamではなくFileStreamなら2GBの上限にひっかからなそうですが、いかがでしょうか?
(たぶんここで出てくる配列云々とは、MemoryStreamが内部で持っている配列のサイズですよね)

一旦ファイルに書き出した後、それをZIP圧縮すればやりたいことは実現できるのではないかと。

※ただ、nskydivingさんがおっしゃるように、小容量のシリアライズ形式を検討を私もおすすめしたいですが。

投稿2020/03/13 08:43

takabosoft

総合スコア8356

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.45%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問