over/core/file.py

103 lines
2.1 KiB
Python

#! /usr/bin/env python3
# encoding: utf-8
import os
from .aux import _print
from .text import prefix
# --------------------------------------------------
class File:
'''
A binary r/w file container that abstracts file descriptors away. You just read and write data.
Nonexistent files will be created, including any directories if necessary.
'''
def __init__(self, path, encoding=None):
'''
encoding which encoding to use when opening files; None means binary (raw)
'''
self.encoding = encoding
if path[0] == '~':
self.path = os.path.join(os.getenv('HOME'), path[2:])
else:
self.path = path
if not os.path.isfile(self.path):
if os.path.exists(self.path):
_print('path §y%s§/ exists but §ris not a file§/' %(self.path), prefix.fail)
raise RuntimeError
else:
dirname = os.path.dirname(self.path)
if dirname and not os.path.isdir(dirname):
_print('creating directory §B%s§/' %(dirname))
os.makedirs(dirname)
# create the file
touch(self.path)
@property
def data(self):
'''
Reads the file and returns the contents.
'''
if self.encoding:
fd = open(self.path, encoding=self.encoding)
else:
fd = open(self.path, 'rb')
data = fd.read()
fd.close()
return data
@data.setter
def data(self, data):
'''
Writes data into the file.
'''
if self.encoding:
fd = open(self.path, 'w', encoding=self.encoding)
else:
fd = open(self.path, 'wb')
fd.write(data)
fd.close()
def __repr__(self):
return 'over.core.File(%s %s)' %(self.path, self.encoding if self.encoding else 'raw')
# --------------------------------------------------
def touch(fname, times=None):
'''
Sets a filename's atime and mtime.
times is a tuple of (atime, mtime) and defaults to 'now'.
'''
with open(fname, 'a'):
os.utime(fname, times)
# --------------------------------------------------
def count_lines(filename):
'''
A reasonably fast and memory-lean line counter.
'''
lines = 0
buffer = bytearray(2048)
with open(filename, 'rb') as f:
while f.readinto(buffer):
lines += buffer.count(b'\n')
return lines