def slice_file(path, size, offset=0, whence=0, output_dir=None, slice_name=None, slice_ext=None): """Write a new file from a slice of an existing file Args: path (str): Path of existing file. size (int): Read length in bytes. offset (int): (optional) Offset from the whence position. Defaults to 0. whence (int): (optional) Originating file seek position. 0 - Absolute, 1 - Current, 2 - End of file. Defaults to 0. output_dir (str): (optional) Path to the directory where new file is saved. slice_name (str): (optional) File name of the slice file. Defaults to the full file's name (with extension). slice_ext (str): (optional) File extension of the slice file. Defaults to 'slice_oYYwXX' where YY and XX are the offset and whence respectively. Returns: str: File path of slice file. """ if not is_str_not_empty(path): raise ValueError("file path must be a string") if not is_int_pos(size): raise ValueError("size must be a positive integer") if not is_int_not_neg(offset): raise ValueError("offset must be a non negative integer") if whence not in [0,1,2]: raise ValueError("whence must be 0 - Absolute, 1 - Current, 2 - End of file") output_dir = os.path.abspath('.') if output_dir is None else os.path.abspath(output_dir) ext = slice_ext if is_str_not_empty(slice_ext) else 'slice_o' + str(offset) + 'w' + str(whence) name = slice_name if is_str_not_empty(slice_name) else os.path.split(path)[1] slice_path = os.path.abspath(os.path.join(output_dir, name + '.' + ext)) write_file(slice_path, read_file(path, size, offset, whence)) return slice_path
def read_file(path, size=None, offset=0, whence=0): """Read a file in binary mode Args: path (str): Path of file. size (int): Read length in bytes. Defaults to None. offset (int): (optional) Offset from the whence position. Defaults to 0. whence (int): (optional) Originating file seek position. 0 - Absolute, 1 - Current, 2 - End of file. Defaults to 0. Returns: str: Binary data. """ if not is_str_not_empty(path): raise ValueError("file path must be a string") if not is_int_not_neg(offset): raise ValueError("offset must be a positive integer") if whence not in [0,1,2]: raise ValueError("whence must be 0 - Absolute, 1 - Current, 2 - End of file") f = open(path, 'rb') f.seek(offset, whence) if size is None: data = f.read() else: data = f.read(size) f.close() return data
def list_dir(dir=".", recurse=True, depth=0, get_file=True, get_dir=True): """Search a directory for files and directories Args: dir (str): (optional) Directory to search. Suggestion: use absolute path. Defaults to current working directory. recurse (bool): (optional) Recursive search flag. Defaults to True. depth (int): (optional) Set the recursion depth. Defaults to 0, which has a max of Python's recursion limit. get_dir (bool): (optional) Return entry for directory. Defaults to True. get_file (bool): (optional) Return entry for file. Defaults to True. Returns: list: List of strings of paths for files and directories. """ if not is_str_not_empty(dir): raise ValueError("dir must be a non empty string") if not os.path.isdir(dir): raise ValueError("dir must be a valid directory") if not is_bool(recurse): raise TypeError("recurse must be True or False") if is_int_neg(depth): raise ValueError("depth must be >= 0") if not is_bool(get_file): raise TypeError("get_file must be True or False") if not is_bool(get_dir): raise TypeError("get_dir must be True or False") list = [] i = 0 if recurse == True: os_walk = os.walk(dir, topdown=True) for root, dirs, files in os_walk: if get_file == True: for name in files: list.append(os.path.join(os.path.abspath(root), name)) if get_dir == True: for name in dirs: list.append(os.path.join(os.path.abspath(root), name)) i += 1 if depth == i: break else: listdir = os.listdir(dir) for name in listdir: path = os.path.join(os.path.abspath(dir), name) if get_dir == True and get_file == True: list.append(path) elif get_file == True and os.path.isfile(path) == True: list.append(path) elif get_dir == True and os.path.isdir(path) == True: list.append(path) return list
def hash_file(hash_name, path, size=None, offset=0, whence=0): """Return the hash of a file Args: hash_name (str): Hash algorithm name. See :py:mod:`hashlib` path (str): Path of file. size (int): (optional) Read length in bytes. Defaults to None. offset (int): (optional) Offset from the whence position. Defaults to 0. whence (int): (optional) Originating file seek position. 0 - Absolute, 1 - Current, 2 - End of file. Defaults to 0. Returns: str: Hash (hex) string. """ if not is_str_not_empty(hash_name): raise ValueError("hash_name must be a string") if not is_str_not_empty(path): raise ValueError("file path must be a string") if not is_int_not_neg(offset): raise ValueError("offset must be a positive integer") if whence not in [0,1,2]: raise ValueError("whence must be 0 - Absolute, 1 - Current, 2 - End of file") data = read_file(path, size, offset, whence) alg = getattr(hash, hash_name.lower()) return alg(data)
def find_file(re_filter=None, branch=".", recurse=True, depth=0, get_file=True, get_dir=True, case_i=True): """Search a branch directory for files and / or directories whose name matches one or more of the filter patterns Args: branch (str): (optional) Directory to search. Suggestion: use absolute path. Defaults to current working directory. re_filter (list): (optional) List of strings of wildcard patterns. Defaults to None, which skips any filtering. recurse (bool): (optional) Recursive search flag. Defaults to True. depth (int): (optional) Set the recursion depth. Defaults to 0, which has a max of Python's recursion limit. get_file (bool): (optional) Return entry for file. Defaults to True. get_dir (bool): (optional) Return entry for directory. Defaults to True. case_i (bool): (optional) Case insensitive search. Defaults to True. Returns: list: List of strings with paths of files. """ if not is_str_not_empty(branch): raise ValueError("branch must be a non empty string") if not os.path.isdir(branch): raise ValueError("branch must be a valid directory") if not is_bool(recurse): raise ValueError("recurse must be True or False") if is_int_neg(depth): raise ValueError("depth must be >= 0") if not is_bool(get_file): raise ValueError("get_file must be True or False") if not is_bool(get_dir): raise ValueError("get_dir must be True or False") if not is_bool(case_i): raise ValueError("case_i must be True or False") search_results = list_dir(branch, recurse, depth, get_file, get_dir) if re_filter is None or len(re_filter) < 1: return search_results elif re_filter == "*": return search_results elif is_list(re_filter) and "*" in re_filter: return search_results if is_str(re_filter): re_filter = [re_filter] re_flag = 0 if case_i: re_flag = re.IGNORECASE bre = partial(wildcard_re, wildcard="*", escape="\\") return list_filter(map(bre, re_filter), search_results, re_flag)
def find_file_re(re_filter=None, branch=".", recurse=True, depth=0, get_file=True, get_dir=True, re_flag=0): """Search a branch directory for files and / or directories whose name matches one or more of the regex filter patterns Args: branch (str): (optional) Directory to search. Suggestion: use absolute path. Defaults to current working directory. re_filter (list): (optional) List of strings of regular expression patterns. Defaults to None, which skips any filtering. recurse (bool): (optional) Recursive search flag. Defaults to True. depth (int): (optional) Set the recursion depth. Defaults to 0, which has a max of Python's recursion limit. get_file (bool): (optional) Return entry for file. Defaults to True. get_dir (bool): (optional) Return entry for directory. Defaults to True. re_flag (int): (optional) See :py:mod:`re` Returns: list: List of strings with paths of files. """ if not is_str_not_empty(branch): raise ValueError("branch must be a non empty string") if not os.path.isdir(branch): raise ValueError("branch must be a valid directory") if not is_bool(recurse): raise TypeError("recurse must be True or False") if is_int_neg(depth): raise ValueError("depth must be >= 0") if not is_bool(get_file): raise ValueError("get_file must be True or False") if not is_bool(get_dir): raise ValueError("get_dir must be True or False") search_results = list_dir(branch, recurse, depth, get_file, get_dir) if re_filter is None or len(re_filter) < 1: return search_results if is_str(re_filter): re_filter = [re_filter] return list_filter(re_filter, search_results, re_flag)
def write_file(path, data, mode='new', offset=0, whence=0): """Write a file in binary mode Args: path (str): Path of file. data (str): Data to be written. mode (str): (optional) 'new' for a new or replacement file. 'insert' for writing more data into a file. 'overwrite' for writing new data over a file. 'append' for adding to the end of a file. Defaults to 'new'. offset (int): (optional) Offset from the whence position. Defaults to 0. whence (int): (optional) Originating file seek position. 0 - Absolute, 1 - Current, 2 - End of file. Defaults to 0. Returns: str: File path to written file. """ if not is_str_not_empty(path): raise ValueError("file path must be a string") if not is_str_not_empty(data): raise ValueError("data must be a string") if mode not in ['new','insert','overwrite','append']: raise ValueError("mode must be 'new' or 'insert' or 'overwrite' or 'append'") if not is_int_not_neg(offset): raise ValueError("offset must be a non negative integer") if whence not in [0,1,2]: raise ValueError("whence must be 0 - Absolute, 1 - Current, 2 - End of file") path = os.path.abspath(path) #: create the directory path to the file if it doesn't exist if not os.path.exists(os.path.split(path)[0]): mode = 'new' os.makedirs(os.path.split(path)[0]) #: stop an attempt to overwrite a directory elif os.path.isdir(path) == True: raise ValueError('may not write file over a directory: ' + path) if mode == 'append': offset = 0 whence = 2 if mode == 'insert' or mode == 'overwrite' or mode == 'append': original_file_size = os.stat(path).st_size original_file = open(path, 'rb') #: determine the offset position for the write action original_file.seek(offset, whence) start_pos = original_file.tell() original_file.seek(0, 0) #: create a temporary file temp_file = open(path + '.tmp', 'wb') #: write any offset data if start_pos > 0: temp_file.write(original_file.read(start_pos)) #: write new data temp_file.write(data) temp_file.flush() os.fsync(temp_file.fileno()) temp_file.close() temp_file_size = os.stat(path + '.tmp').st_size #: write any remaining data from the original file if mode == 'overwrite' and temp_file_size < original_file_size: temp_file = open(path + '.tmp', 'ab') original_file.seek(temp_file_size, 0) temp_file.write(original_file.read()) temp_file.flush() os.fsync(temp_file.fileno()) temp_file.close() elif mode == 'insert': temp_file = open(path + '.tmp', 'ab') original_file.seek(start_pos, 0) temp_file.write(original_file.read()) temp_file.flush() os.fsync(temp_file.fileno()) temp_file.close() original_file.close() #: replace the original file os.rename(path + '.tmp', path) elif mode == 'new': f = open(path, 'wb') f.write(data) f.flush() os.fsync(f.fileno()) f.close() return path