文字列numpy.memmap
の大規模なディスクベースの配列をメモリにマップするために使用することは可能ですか?
フロートなどでできることは知っていますが、この質問は特に文字列に関するものです。
固定長文字列と可変長文字列の両方のソリューションに興味があります。
このソリューションは、適切なファイル形式を自由に指定できます。
文字列numpy.memmap
の大規模なディスクベースの配列をメモリにマップするために使用することは可能ですか?
フロートなどでできることは知っていますが、この質問は特に文字列に関するものです。
固定長文字列と可変長文字列の両方のソリューションに興味があります。
このソリューションは、適切なファイル形式を自由に指定できます。
「配列」という用語で示唆されているように、すべての文字列の長さが同じである場合、これは簡単に可能です。
a = numpy.memmap("data", dtype="S10")
長さ10の文字列の例になります。
編集:明らかに文字列の長さが同じではないため、O(1)アイテムへのアクセスを許可するためにファイルにインデックスを付ける必要があります。これには、ファイル全体を1回読み取り、すべての文字列の開始インデックスをメモリに保存する必要があります。残念ながら、最初にメモリ内のファイルと同じサイズの配列を作成せずに、純粋なNumPyのインデックス作成方法はないと思います。ただし、この配列は、インデックスを抽出した後に削除できます。
最も柔軟なオプションは、データベースまたはその他のより複雑なディスク上のファイル構造に切り替えることです。
ただし、ファイルをプレーン テキスト ファイルとして保持するほうがよい理由がおそらくあります...
ファイルの作成方法を制御できるため、1 つのオプションは、他のファイル内の各文字列の開始位置 (バイト単位) のみを含む 2 番目のファイルを単純に書き出すことです。
これにはもう少し作業が必要ですが、基本的には次のようなことができます。
class IndexedText(object):
def __init__(self, filename, mode='r'):
if mode not in ['r', 'w', 'a']:
raise ValueError('Only read, write, and append is supported')
self._mainfile = open(filename, mode)
self._idxfile = open(filename+'idx', mode)
if mode != 'w':
self.indicies = [int(line.strip()) for line in self._idxfile]
else:
self.indicies = []
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self._mainfile.close()
self._idxfile.close()
def __getitem__(self, idx):
position = self.indicies[idx]
self._mainfile.seek(position)
# You might want to remove the automatic stripping...
return self._mainfile.readline().rstrip('\n')
def write(self, line):
if not line.endswith('\n'):
line += '\n'
position = self._mainfile.tell()
self.indicies.append(position)
self._idxfile.write(str(position)+'\n')
self._mainfile.write(line)
def writelines(self, lines):
for line in lines:
self.write(line)
def main():
with IndexedText('test.txt', 'w') as outfile:
outfile.write('Yep')
outfile.write('This is a somewhat longer string!')
outfile.write('But we should be able to index this file easily')
outfile.write('Without needing to read the entire thing in first')
with IndexedText('test.txt', 'r') as infile:
print infile[2]
print infile[0]
print infile[3]
if __name__ == '__main__':
main()