aux-dbf
Version:
DBF for price PSM
255 lines (217 loc) • 8.28 kB
text/typescript
import { Column, COLUMN_TYPE } from "./Column";
import { Row } from "./Row";
import { NodeIndex } from "./NodeIndex";
import { isUndefined } from "util";
import { BTree } from "./BTree";
import { DBF_TABLE_TYPE } from "./DBF_TABLE_TYPE";
import { DBF_MODE } from "./DBF_MODE";
import { DBFReader } from "./DBFReader";
import { DBF4Reader } from "./DBF4Reader";
import { DBF7Reader } from "./DBF7Reader";
const iconv = require("iconv-lite");
var fs = require("fs");
/**
* Проверять, является ли переменная val строкой
* @param val
* @return {boolean}
*/
function isString(val) {
return (typeof val === "string" || val instanceof String);
}
/**
* DZHIGURDA A. (c) 2017
* OOO "PIKADA-LAB"
* Version 0.0.3-DEV
*/
export class DBFLib {
/** Счётчик символов */
private i: number;
/** Сколько в строке символов */
private iLine: number;
// Заголовочные данные
/** Тип таблицы */
public TypeTable: DBF_TABLE_TYPE;
private RecordsCount: number;
/** Полная длина заголовка включая дескриптор */
private HeaderSize: number;
/** Длина одной записи */
private RecordSize: number;
/** Наличие кодировки */
private Encode: number;
// Сигнатура
/** Кол-во колонок */
private countColumn: number; // Кол-во колонок
/** Ссылка на файл */
private file: File;
/** Колонки */
private col: Column[];
/** Данные */
private data: Row[];
/** Массив индексов */
private indexes: BTree[];
public mode: DBF_MODE = DBF_MODE.PROD;
private binFile: Buffer;
protected reader: DBFReader;
protected dataSource: any[][] = [];
constructor(private path: string) {}
public DBFRead(clbk?: (err: any, dbf: DBFLib) => void): void {
try {
if (this.mode == DBF_MODE.TEST) {
console.log("[*] OpenFile. " + this.path + "\n");
}
fs.readFile(this.path, (err: any, file: Buffer) => {
if (err) {
if (err.code === "ENOENT") {
console.log(this.path + " не найден");
if (!isUndefined(clbk)) clbk(this.path + " не найден", null);
return;
}
if (!isUndefined(clbk)) clbk(err, null);
return;
}
if (file.length == 0) return;
this.binFile = file;
if (this.mode == DBF_MODE.TEST) {
console.time("read row");
}
this.checkTableType();
if (this.TypeTable == 3) {
this.reader = new DBF4Reader(file);
} else if (this.TypeTable == 4) {
this.reader = new DBF7Reader(file);
} else {
throw new Error("Формат DBF не поддерживается");
}
this.reader.mode = this.mode;
this.reader.readHeader();
this.reader.readSignature();
this.col = this.reader.getColumns();
this.countColumn = this.col.length;
if (this.mode == DBF_MODE.TEST) {
console.timeEnd("read row");
}
if (!isUndefined(clbk)) clbk(err, this);
});
} catch (ex) {
if (!isUndefined(clbk)) clbk(ex, null);
}
}
public readRows() {
this.dataSource = this.reader.readTable();
this.indexes = new Array(this.Count()).fill(null);
}
public Exist(): boolean {
return this.file != null;
}
/** Название стобца по номеру */
public getRowName(index: number): string {
return this.col[index].getTitle();
}
/** Строка по номеру строки и номеру столбца */
public getRow(rowIndex: number, colIndex: number | string): string | Buffer {
if (rowIndex == null || colIndex == null) {
throw "Индекс не определён " + rowIndex + "x" + colIndex;
}
this.checkRow(rowIndex);
if ( isString(colIndex) ) {
colIndex = (colIndex as string).toLowerCase();
let l = 0;
for (l = 0; l < this.countColumn; l++) {
if (this.col[l].getTitle().toLowerCase() == colIndex) break;
}
if (l == this.countColumn) throw "Индекс за пределом доступного количества колонок. Доступное значение от 0 до " + (this.col.length - 1);
return this.data[rowIndex][l];
} else {
if (!this.checkColumn(+colIndex)) throw "Индекс за пределом доступного количества колонок. Доступное значение от 0 до " + (this.col.length - 1);
return this.dataSource[rowIndex][colIndex];
}
}
public getString(rowIndex: number, colIndex: number | string) {
if (isString(colIndex)) {
colIndex = (colIndex as string).toLowerCase();
let l = 0;
for (l = 0; l < this.countColumn; l++) {
if (this.col[l].getTitle().toLowerCase() == colIndex) break;
}
if (l == this.countColumn) throw "Индекс за пределом доступного количества колонок. Доступное значение от 0 до " + (this.col.length - 1);
colIndex = l;
}
if (this.getRow(rowIndex, colIndex) instanceof Buffer) {
return iconv.decode(Buffer.from(this.getRow(rowIndex, colIndex) as string, "binary"), "win1251").trim();
} else {
this.checkAccess(rowIndex, colIndex);
return this.getRow(rowIndex, colIndex).toString();
}
}
public getInt(rowIndex: number, colIndex: number | string): number {
if (isString(colIndex)) {
colIndex = (colIndex as string).toLowerCase();
let l = 0;
for (l = 0; l < this.countColumn; l++) {
if (this.col[l].getTitle().toLowerCase() == colIndex) break;
}
if (l == this.countColumn) throw "Индекс за пределом доступного количества колонок. Доступное значение от 0 до " + (this.col.length - 1);
this.checkAccess(rowIndex, l);
return +this.dataSource[rowIndex][l];
} else {
this.checkAccess(rowIndex, colIndex);
return +this.dataSource[rowIndex][colIndex];
}
// return +this.data[rowIndex].value[colIndex];
}
private checkAccess(rowIndex, colIndex) {
if (!this.checkRow(rowIndex)) throw "Индекс за пределом доступного количества строк. Доступное значение от 0 до " + (this.Count() - 1);
if (!this.checkColumn(colIndex)) throw "Индекс за пределом доступного количества колонок. Доступное значение от 0 до " + (this.CountColumn() - 1);
}
/** Количество строк */
public Count(): number {
return this.dataSource.length;
}
/** Количество колонок */
public CountColumn(): number {
return this.col.length;
}
public SetBTree(columnIndex: number): void {
if (this.mode == DBF_MODE.TEST) {
console.time("add index " + columnIndex);
}
this.indexes[columnIndex] = new BTree();
for (let i = 0; i < this.Count(); i++) {
this.indexes[columnIndex].insert(this.getInt(i, columnIndex), i);
}
if (this.mode == DBF_MODE.TEST) {
console.timeEnd("add index " + columnIndex);
}
}
public Search(l: number, value: number): number {
let i: number;
if (this.indexes[l]) {
// console.log("[*] Whith index");
const index: NodeIndex = this.indexes[l].search(value);
if (!index) return null;
const i: number = index.Adress;
if (!i) return null;
return i;
}
// console.log("[X] Whith index");
for (let key = 0; key < this.Count(); key++) {
if (this.getInt(key, l) == value) {
return key;
}
}
return null;
}
/// PRIVATE
private checkRow(index: number) {
return index < this.dataSource.length;
}
private checkColumn(index: number) {
return index < this.col.length;
}
/**
* Задаёт байт для определения типа таблицы
*/
private checkTableType(): void {
this.TypeTable = this.binFile.readInt8(0);
}
}