3
This file is part of HTD (HayzenTech Database)
5
Copyright (C) 2011 - 2013 Andrew Hayzen
7
HTD is free software: you can redistribute it and/or modify
8
it under the terms of the GNU Lesser General Public License as published by
9
the Free Software Foundation, either version 3 of the License, or
10
(at your option) any later version.
12
HTD is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU Lesser General Public License for more details.
17
You should have received a copy of the GNU Lesser General Public License
18
along with HTD. If not, see <http://www.gnu.org/licenses/>
20
This document conforms to the PEP 8 Style Guide
23
from ..._base.file import location_is_file, FileTools, LockFile
25
from os import name, rename, unlink
26
from os.path import exists
27
from struct import pack, unpack
28
from sys import platform
31
if platform == 'linux2':
37
class FileWriter(LockFile):
38
def __init__(self, location, header, new):
39
LockFile.__init__(self)
41
self.location = location
42
self.offset = 0 # Offset until data
43
self.width = 0 # Width of a record
44
self.update_file_settings(header)
46
def __delitem__(self, index):
47
""" Remove the data or mark as deleted """
49
self.delete_region(index, index + 1)
51
def __getitem__(self, index):
52
""" Get the data for the index """
54
self.file.seek((index * self.width) + self.offset + 8)
55
return self.file.read(self.width - 8)
57
def __setitem__(self, index, data):
58
""" Set the data for the index """
60
self.file.seek((index * self.width) + self.offset + 8)
64
""" Number of items in the file """
67
return (self.file.tell() - self.offset) // self.width
69
def close(self, delete_files):
70
if exists(self.location):
73
self.close_lock_file(delete_files) # Deletes this file too
75
def copy(self, location, replace):
76
if replace is False and exists(location):
77
raise IOError("Path already exists")
79
if not location_is_file(location):
80
raise ValueError("Location is not valid for this file format")
82
with open(location, "wb") as f:
84
f.write(self.file.read())
86
def delete_region(self, start, stop):
87
""" Delete a region of data """
91
FileTools.delete_region(self.file, (start * self.width) + self.offset,
92
(stop * self.width) + self.offset)
94
def flush(self, fsync=False):
95
if self.file is not None:
101
def get_version(self, index):
102
""" Get the version of the index """
104
self.file.seek((index * self.width) + self.offset)
106
return unpack("Q", self.file.read(8))[0]
108
def insert(self, index, data):
109
""" Insert the item into an index """
111
position = (index * self.width) + self.offset
113
data = b"".join([b"\x00" * 8, data]) # Insert blank version
115
FileTools.insert_region(self.file, position, data)
117
def iterate(self, i, stop):
118
""" Iterate over a region in the file """
122
while reading and i < stop:
123
self.file.seek((i * self.width) + self.offset)
124
data = self.file.read(self.width)
125
reading = data != b""
128
yield unpack("Q", data[:8])[0], data[8:]
132
def left(self, index, binary_search=False):
134
Get the index to the left of the index
135
binary_search=True get the real left
136
binary_search=False get the data left
144
def rename(self, location, replace):
145
if replace is False and exists(location):
146
raise IOError("Cannot rename because path already exists")
148
if replace and name == "nt": # Windows only rename if dst !exist
151
rename(self.location, location) # Rename the file
153
def right(self, index, binary_search=False):
155
Get the index to the right of the index
156
binary_search=True get the real right
157
binary_search=False get the data right
160
if index + 1 < len(self):
165
def set_left(self, index):
166
""" Set the index to the left of the item """
168
return True # File is ordered so no need for setting positioning
170
def set_right(self, index):
171
""" Set the index to the right of the item """
173
return True # File is ordered so no need for setting positioning
175
def set_version(self, index, version):
176
""" Set the version of an index """
178
self.file.seek((index * self.width) + self.offset)
179
self.file.write(pack("Q", version or 0))
183
def update_file_settings(self, header):
184
""" Update the file settings from the header info """
186
self.offset = header["SIZ"]
187
self.width = sum([header["ATT"][i].size + 1
188
for i in header["ATT"]]) + 8