使用 NodeJS 編寫前端工具時,操作得最多的是文本文件,因此也就涉及到了文件編碼的處理問題。我們常用的文本編碼有 UTF8 和 GBK 兩種,並且 UTF8 文件還可能帶有 BOM。在讀取不同編碼的文本文件時,需要將文件內容轉換為 JS 使用的 UTF8 編碼字元串後才能正常處理。
1、BOM 的移除
BOM 用於標記一個文本文件使用 Unicode 編碼,其本身是一個 Unicode 字元("uFEFF"),位於文本文件頭部。在不同的 Unicode 編碼下,BOM 字元對應的二進制位元組如下:
3、單位元組編碼
有時候,我們無法預知需要讀取的文件採用哪種編碼,因此也就無法指定正確的編碼。比如我們要處理的某些 CSS 文件中,有的用 GBK 編碼,有的用 UTF8 編碼。雖然可以一定程度可以根據文件的位元組內容猜測出文本編碼,但這里要介紹的是有些局限,但是要簡單得多的一種技術。
首先我們知道,如果一個文本文件只包含英文字元,比如 Hello World,那無論用 GBK 編碼或是 UTF8 編碼讀取這個文件都是沒問題的。這是因為在這些編碼下,ASCII0~128 范圍內字元都使用相同的單位元組編碼。
反過來講,即使一個文本文件中有中文等字元,如果我們需要處理的字元僅在 ASCII0~128 范圍內,比如除了注釋和字元串以外的JS代碼,我們就可以統一使用單位元組編碼來讀取文件,不用關心文件的實際編碼是 GBK 還是 UTF8。
B. nodejs判斷第一個字元是否是絕對路徑
nodejs判斷第一個字元是否是絕對路徑處理方法為:
1、dirname表示當前文件所在的目錄的絕對路徑。
2、filename表示當前文件的絕對路徑。
C. nodejs檢查文件是否含有mp4
用exists方法檢查。
可以用exists方法檢查MP4文件是否存在,有兩個參數分別為文件路徑與回調函數。其中回調函數中參數為布爾值,表示文件是否存在。
Node.js是一個開源和跨平台的javaScript運行時環境。它幾乎是任何類型項目的流行工具。Node.js在瀏覽器之外運行V8JavaScript引擎(GoogleChrome的內核)。這使得Node.js的性能非常好。Node.js應游鉛用程序在單個進程中運行,無需為每個請求創建新的線程。Node.js在其標准庫中提供了一組非同步的I/O原語,以防止JavaScript代碼阻塞,通常,Node.js中的庫是使用非阻塞範式編寫的,使得阻塞行為成為異常而不是常態。當Node.js執行I/O操作時(比如從網路讀取、訪問資料庫或文件系統),Node.js將在響應返回時恢復操作(而不是阻塞線程和浪費CPU周渣前期等待)。這允許Node.js使用單個服務神梁好器處理數千個並發連接,而不會引入管理線程並發(這可能是錯誤的重要來源)的負擔。
D. nodejs刪除安卓手機指定文件
nodejs刪除安卓手機指定文件
* 刪除目錄下 指定 文件方法
* 參數: dir 文件夾名稱
* fs.stat => 判斷是文件還是文件夾
* fs.unlink => 刪除文件
* fs.readdir => 讀取文件夾內容
*/
const fs = require('fs')
const path = require('path')
const deleteFiles = function (dir) {
fs.readdir(dir, function (err, files) {
files.forEach(function (filename) {
var src = path.join(dir, filename)
fs.stat(src, function (err, st) {
if (err) {
throw err
}
// 判斷是否為文件
if (st.isFile()) {
// 這里可以使用正則,也可以使用其他方法,比如字元串處理等,/\.d\.ts$/
if (/\.we$/.test(filename)) {
fs.unlink(src, err => {
if (err) throw err
console.log('成功刪除:' + src)
})
}
} else {
// 遞歸文件夾
deleteFiles(src)
}
})
})
})
}
deleteFiles('./')
復制代碼
修改文件名稱
復制代碼
fs = require('fs') // 引用文件系統模塊
const PATH = `./src/` // 當前文件夾
const readFileList = function (path, filesList) {
filesList = filesList || []
let files = fs.readdirSync(path)
files.forEach(function (filename, index) {
// const stat = fs.statSync(path + filename); //讀取的文件信息
// isDirectory 判斷是不是目錄
if (fs.statSync(path + filename).isDirectory()) {
// 遞歸讀取文件
readFileList(`${path}${filename}/`, filesList)
} else {
filesList.push({
path, // 路徑
filename // 名字
})
}
})
return filesList
}
// 修改文件名稱
const rename = function (oldPath, newPath, filename, newSuffixFile) {
fs.rename(oldPath, newPath, function (err) {
if (err) {
throw err
}
console.log(`${filename} 修改為 => ${newSuffixFile}`)
})
}
// 批量修改文件名稱
const getChangeFiles = function (path, oldSuffix, newSuffix) {
if (!oldSuffix && !newSuffix) {
console.log(`後綴未設置`)
}
this.readFileList(path).forEach(item => {
if (item.filename.indexOf(oldSuffix) > -1) {
console.log(item.filename)
let oldPath = item.path + item.filename,
newSuffixFile = item.filename.split(oldSuffix)[0] + newSuffix,
newPath = item.path + newSuffixFile
rename(oldPath, newPath, item.filename, newSuffixFile)
}
})
}
getChangeFiles(PATH, `.we`, `.js`)
// 引入fs文件處理模塊
const fs = require('fs')
// 現在我們要關心的是『icons『文件夾
// 我們不妨用變數表示這個文件夾名稱,方便日後維護和管理
const src = 'dist'
// API文檔中中找到遍歷文件夾的API
// 找到了,是fs.readdir(path, callback)
// 文檔中有敘述:
// 讀取 path 路徑所在目錄的內容。 回調函數 (callback) 接受兩個參數 (err, files) 其中 files 是一個存儲目錄中所包含的文件名稱的數組
// 因此:
fs.readdir(src, function (err, files) {
// files是名稱數組,因此
// 可以使用forEach遍歷哈, 此處為ES5 JS一點知識
// 如果不清楚,也可以使用for循環哈
files.forEach(function (filename) {
// 下面就是文件名稱重命名
// API文檔中找到重命名的API,如下
// fs.rename(oldPath, newPath, callback)
// 下面,我們就可以依葫蘆畫瓢,確定新舊文件名稱:
const oldPath = src + '/' + filename
// newPath = src + 『/『 + filename.replace(/_/g, 『-『);
const newPath = src + '/' + 'index.html'
if (filename === 'Homepad.html') {
// 重命名走起
fs.rename(oldPath, newPath, function (err) {
if (!err) {
console.log(filename + '重命名成功!')
}
})
}
})
})
復制代碼
E. nodejs編譯後js文件名前綴
Node.js 是一個基於 Chrome V8 引擎的 JavaScript 運行環境。
Node與javaScript的區別在於,javaScript的頂層對象是window,而node是global
//這里使用的var聲明的變數不是全局的,是當前模塊下的,用global聲明的表示是全局的
var s = 100;
global.s = 200;
//這里訪問到的s是var生命的
console.log(s); //100
//這里訪問到的才是全局變數
console.log(global.s); //200
模塊:在node中,文件和模塊是一一對應的,也就是一個文件就是一個模塊;每個模塊都有自己的作用域,我們通過var申明的變數並非全局而是該模塊作用域下的。
(2)mole模塊
1、文件查找
1)首先按照載入的模塊的文件名稱進行查找,如果沒有找到,則會帶上 .js、.json 或 .node 拓展名在載入
2)以 '/' 為前綴的模塊是文件的絕對路徑。 例如,require('/home/marco/foo.js') 會載入 /home/marco/foo.js 文件。
3)以 './' 為前綴的模塊是相對於調用 require() 的文件的。 也就是說,circle.js 必須和 foo.js 在同一目錄下以便於 require('./circle') 找到它。
4)當沒有以 '/'、'./' 或 '../' 開頭來表示文件時,這個模塊必須是一個核心模塊或載入自 node_moles 目錄。
5)如果給定的路徑不存在,則 require() 會拋出一個 code 屬性為 'MODULE_NOT_FOUND' 的 Error。
2、mole 作用域
在一個模塊中通過var定義的變數,其作用域范圍是當前模塊,外部不能夠直接的訪問,如果我們想一個模塊能夠訪問另外一個模塊中定義的變數,可以有一下兩種方式:
1)把變數作為global對象的一個屬性,但這樣的做法是不推薦的
2)使用模塊對象 mole。mole保存提供和當前模塊有關的一些信息。
在這個mole對象中有一個子對象exports對象,我們可以通過這個對象把一個模塊中的局部變數對象進行提供訪問。
//這個方法的返回值,其實就是被載入模塊中的mole.exports
require('./02.js');
3、__dirname:當前模塊的目錄名。
例子,在 /Users/mjr 目錄下運行 node example.js:
console.log(__dirname);
// 輸出: /Users/mjr
console.log(path.dirname(__filename));
// 輸出: /Users/mjr
4、__filename:當前模塊的文件名(處理後的絕對路徑)。當前模塊的目錄名可以使用 __dirname 獲取。
在 /Users/mjr 目錄下運行 node example.js:
console.log(__filename);
// 輸出: /Users/mjr/example.js
console.log(__dirname);
// 輸出: /Users/mjr
(3)process(進程)
process 對象是一個全局變數,提供 Node.js 進程的有關信息以及控制進程。 因為是全局變數,所以無需使用 require()。
1、process.argv
返回進程啟動時的命令行參數。第一個元素是process.execPath。第二個元素是當前執行的JavaScript文件的路徑。剩餘的元素都是額外的命令行參數。
console.log(process.argv);
列印結果:
2、process.execPath返回啟動進程的可執行文件的絕對路徑。
3、process.env 返回用戶的環境信息。
在process.env中可以新增屬性:
process.env.foo = 'bar';
console.log(process.env.foo);
可以通過delete刪除屬性:
delete process.env.foo;
console.log(process.env);
在Windows上,環境變數不區分大小寫
4、process.pid 屬性返回進程的PID。
5、process.platform屬性返回字元串,標識Node.js進程運行其上的操作系統平台。
6、process.title 屬性用於獲取或設置當前進程在 ps 命令中顯示的進程名字
7、process.uptime() 方法返回當前 Node.js 進程運行時間秒長
注意: 該返回值包含秒的分數。 使用 Math.floor() 來得到整秒鍾。
8、process.versions屬性返回一個對象,此對象列出了Node.js和其依賴的版本信息。
process.versions.moles表明了當前ABI版本,此版本會隨著一個C++API變化而增加。 Node.js會拒絕載入模塊,如果這些模塊使用一個不同ABI版本的模塊進行編譯。
9、process對象-輸入輸出流
var a;
var b;
process.stdout.write('請輸入a的值: ');
process.stdin.on('data', (chunk) => {
if (!a) {
a = Number(chunk);
process.stdout.write('請輸入b的值:');
}else{
b = Number(chunk);
process.stdout.write('a+b的值:'+(a+b));
process.exit();
}
});
(4)Buffer緩沖器
Buffer類,一個用於更好的操作二進制數據的類,我們在操作文件或者網路數據的時候,其實操作的就是二進制數據流,Node為我們提供了一個更加方便的去操作這種數據流的類Buffer,他是一個全局的類
1、如何創建使用buffer
Buffer.from(array) 返回一個 Buffer,包含傳入的位元組數組的拷貝。
Buffer.from(arrayBuffer[, byteOffset [, length]]) 返回一個 Buffer,與傳入的 ArrayBuffer 共享內存。
Buffer.from(buffer) 返回一個 Buffer,包含傳入的 Buffer 的內容的拷貝。
Buffer.from(string[, encoding]) 返回一個 Buffer,包含傳入的字元串的拷貝。
Buffer.alloc(size[, fill[, encoding]]) 返回一個指定大小且已初始化的 Buffer。 該方法比 Buffer.allocUnsafe(size) 慢,但能確保新創建的 Buffer 不會包含舊數據。
Buffer.allocUnsafe(size) 與 Buffer.allocUnsafeSlow(size) 返回一個指定大小但未初始化的 Buffer。 因為 Buffer 是未初始化的,可能包含舊數據。
// 創建一個長度為 10、且用 01 填充的 Buffer。
const buf1 = Buffer.alloc(10,1);
// 創建一個長度為 10、且未初始化的 Buffer。
// 這個方法比調用 Buffer.alloc() 更快,但返回的 Buffer 實例可能包含舊數據,因此需要使用 fill() 或 write() 重寫。
const buf2 = Buffer.allocUnsafe(10);
const buf3 = Buffer.from([1, 2, 3]);
const buf4 = Buffer.from('tést');
console.log(buf1); //<Buffer 01 01 01 01 01 01 01 01 01 01>
console.log(buf2); //<Buffer 00 00 00 00 08 00 00 00 07 00>
console.log(buf3); //<Buffer 01 02 03>
console.log(buf4); //<Buffer 74 c3 a9 73 74>
2、Buffer對象提供的toString、JSON的使用
1)buf.toString(encoding,start,end)
var bf = Buffer.from('miaov');
console.log(bf.toString('utf-8',1,4)); //iaov
console.log(bf.toString('utf-8',0,5)); //miaov
console.log(bf.toString('utf-8',0,6)); //miaov
2)buf.write(string,offset,length,encoding)
string 要寫入 buf 的字元串。
offset 開始寫入的偏移量。默認 0,這里指的是buffer對象的起始要寫入的位置。
length 要寫入的位元組數。默認為 buf.length - offset。
encoding string 的字元編碼。默認為 'utf8'。
返回: 已寫入的位元組數。
var str = "miaov hello";
var bf = Buffer.from(str);
var bf2 = Buffer.alloc(8);
//從0開始寫入5個
bf2.write(str,0,5);
console.log(bf);
console.log(bf2);
3)buf.toJSON()
const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);
console.log(json);
// 輸出: {"type":"Buffer","data":[1,2,3,4,5]}
3、Buffer中靜態方法的使用
1)Buffer.isEncoding(encoding) : 判斷是否是Buffer支持的字元編碼,是則返回true,不是則返回false
console.log(Buffer.isEncoding('utf-8')); //true
2)Buffer.isBuffer(obj) :如果 obj 是一個 Buffer,則返回 true,否則返回 false。
(5)fs(文件系統)
該模塊是核心模塊,需要使用require('fs')導入後使用,該模塊主要用來操作文件
1、fs.open(path, flags, mode, callback)
path:要打開的文件的路徑;
flags:打開文件的方式 讀/寫;
mode:設置文件的模式 讀/寫/執行
callback(err,fd):文件打開以後,在回調函數中做相應的處理,回調函數的兩個參數:
err:文件打開失敗的錯誤保存在err裡面,如果成功err為null
fd:被打開文件的標識
var fs = require('fs');
fs.open('./test.txt','r',function(err,fd){
if(err){
console.log("文件打開失敗");
}else{
console.log("文件打開成功");
}
});
2、fs.openSync(path, flags, mode) :返迴文件描述符。
var fs = require('fs');
console.log(fs.openSync('./test.txt','r')); //3
3、fs.read(fd, buffer, offset, length, position, callback)
從 fd 指定的文件中讀取數據;
buffer 指定要寫入數據的 buffer;
offset 指定 buffer 中開始寫入的偏移量;
length 指定要讀取的位元組數;
position 指定文件中開始讀取的偏移量。 如果 position 為 null,則從文件的當前位置開始讀取;
callback 有三個參數 (err, bytesRead, buffer)
示例:test.txt 中的值為123456789
fs.open('./test.txt','r',function(err,fd){
if(!err){
var bf = Buffer.alloc(5);
fs.read(fd,bf,0,5,0,function(){
console.log(bf.toString()); //12345
})
}
});
4、fs.write(fd, buffer, offset, length, position, callback)
將 buffer 寫入到 fd 指定的文件。
offset 指定 buffer 中要開始被寫入的偏移量,length 指定要寫入的位元組數。
position 指定文件中要開始寫入的偏移量。 如果 typeof position !== 'number',則從當前位置開始寫入。
callback 有三個參數 (err, bytesWritten, buffer),其中 bytesWritten 指定 buffer 中已寫入文件的位元組數。
var fs = require('fs');
fs.open('./test.txt','r+',function(err,fd){
if(!err){
var bf = Buffer.alloc(5);
fs.read(fd,bf,0,5,0,function(){
console.log(bf.toString()); //12345
});
var bf = Buffer.from('test數據');
fs.write(fd,bf,0,10,0);
fs.write(fd,'測試數據2',10,'utf-8');
}
});
fs.write(fd, string, position, encoding, callback)
將 string 寫入到 fd 指定的文件。 如果 string 不是一個字元串,則會強制轉換成字元串。
position 指定文件中要開始寫入的偏移量。 如果 typeof position !== 'number',則從當前位置開始寫入。
encoding 指定字元串的編碼。
callback 有三個參數 (err, written, string),其中 written 指定字元串中已寫入文件的位元組數。 寫入的位元組數與字元串的字元數是不同的。
5、fs.exists(path,callback)檢查指定路徑的文件或者目錄是否存在
fs.appendFile(path, data, callback):將數據追加到文件,如果文件不存在則創建文件。
//檢查文件是否存在
var fs = require('fs');
var filename = './test2.txt';
fs.exists(filename,function(isExists){
if(!isExists){
fs.writeFile(filename,'miaov',function(err){
if(err){
console.log("文件創建失敗");
}else{
console.log("文件創建成功");
}
});
}else{
fs.appendFile(filename,'-leo',function(err){
if(err){
console.log("文件內容追加失敗");
}else{
console.log("文件內容追加成功");
}
})
}
});
(6)前端項目自動化構建
1、創建myProject項目文件以及對應的文件夾
var projectData ={
'name':'myProject',
'fileData':[
{
'name':'css',
'type':'dir'
},{
'name':'js',
'type':'dir'
},{
'name':'images',
'type':'dir'
},{
'name':'index.html',
'type':'file',
'content' : '<html>\n\t<head>\n\t\t<title>title</title>\n\t</head>\n\t<body>\n\t\t<h1>Hello</h1>\n\t</body>\n</html>'
}
]
};
var fs = require('fs');
if(projectData.name){
// 創建項目文件夾
fs.mkdirSync(projectData.name);
var fileData = projectData.fileData;
if(fileData && fileData.length){
fileData.forEach(function(file){
//文件或文件夾路徑
file.path = './'+projectData.name +'/'+ file.name;
//根據type類型創建文件或文件夾
file.content = file.content || '';
switch(file.type){
case 'dir':
fs.mkdirSync(file.path);
break;
case 'file':
fs.writeFileSync(file.path,file.content);
break;
default:
break;
}
});
}
}
2、自動打包多個文件
var fs = require('fs');
var filedir = './myProject/dist';
fs.exists(filedir,function(isExists){
if(!isExists){
fs.mkdirSync(filedir);
}
fs.watch(filedir,function(ev,file){
//只要有一個文件發生了變化,我們就需要對文件夾下的所有文件進行讀取、合並
fs.readdir(filedir,function(err,dataList){
var arr = [];
dataList.forEach(function(file){
if(file){
//statSync查看文件屬性
var info = fs.statSync(filedir + '/' +file);
//mode文件許可權
if(info.mode === 33206){
arr.push(filedir + '/' +file);
}
}
});
//讀取數組中的文件內容
var content = '';
arr.forEach(function(file){
var c = fs.readFileSync(file);
content += c.toString()+'\n';
});
//合並文件中的內容
fs.writeFileSync('./myProject/js/index.js',content);
})
});
});
(7)使用node進行web開發
1、搭建一個http的伺服器,用於處理用戶發送的http請求
//載入一個http模塊
var http = require('http');
//通過http模塊下的createServer創建並返回一個web伺服器對象
var server = http.createServer();
//開啟 HTTP 伺服器監聽連接,只有調用了listen方法以後,伺服器才開始工作
server.listen(8000,'localhost');
//伺服器是否正在監聽連接
server.on('listening',function(){
console.log("listening..........");
});
//每次接收到一個請求時觸發,每個連接可能有多個請求(在 HTTP keep-alive 連接的情況下)。
server.on('request',function(){
res.write('<p>hello</p>');
res.end();
});
2、request方法有兩個參數:request、response
1)request:http.IncomingMessage的一個實例,獲取請求的一些信息,如頭信息,數據等
httpVession:使用的http協議的版本
headers:請求頭信息中的數據
url:請求的地址
method:請求的方式
2)response:http.ServerResponse的一個實例,可以向請求的客戶端輸出返回響應
write(chunk,encoding):發送一個數據塊到相應正文中
end(chunk,encoding):當所有的正文和頭信息發送完成以後調用該方法告訴伺服器數據已經全部發送完成了,這個方法在每次完成信息發送以後必須調用,並且是最後調用。
statusCode:該屬性用來設置返回的狀態碼
setHeader(name,value):設置返回頭信息
writeHead(statusCode,reasonPhrase,headers)這個方法只能在當前請求中使用一次,並且必須在response.end()之前調用
3、使用fs模塊實現行為表現分離
var http = require('http');
var url = require('url');
var fs = require('fs');
var server = http.createServer();
//html文件的路徑
var htmlDir = __dirname + '/html/';
server.on('request',function(request,response){
var urlStr = url.parse(request.url);
//根據pathname匹配對應的html文件
switch(urlStr.pathname){
case '/':
sendData(htmlDir + 'index.html',request,response);
break;
case '/user':
sendData(htmlDir + 'user.html',request,response);
break;
case '/login':
sendData(htmlDir + 'login.html',request,response);
break;
default:
//處理其他情況
sendData(htmlDir + 'err.html',request,response );
break;
}
});
function sendData(file,request,response){
//讀取文件,存在則返回對應讀取的內容,不存在則返回錯誤信息
fs.readFile(file,function(err,data){
if(err){
response.writeHead(404,{
'content-type':'text/html;charset=utf-8'
});
response.end('<h1>頁面不存在</h1>')
}else{
response.writeHead(200,{
'content-type':'text/html;charset=utf-8'
});
response.end(data);
}
})
}
server.listen(8000,'localhost');
F. nodejs statSync判斷一個目錄或文件是否存在
nodejs statSync判斷一個目錄橋舉或文件是否存在
獲取目則銀錄下某個文敏盯碧件中的信息 [ { name, photoUrl, ...}, ]
目錄: 項目名稱/app/public/json_tb/user_1/blog_1/commiter_2.json
G. nodejs實現一個word文檔解析器思路詳解
之前項目里遇到一個需求,需要前端上傳一個word文檔,然後後端提取出該文檔的指定位置的內容並保存。這里後端用的是nodejs,開始接到這個需求,發現無從下手,主要是沒有處理過word這種類型的文檔,怎麼解析?
Excel倒是有相關的庫可以用,而且很簡單
思路
搜索了好一會兒,在npm上發現了一個叫做
adm-zip
的包,這個包可以解壓縮word文檔,原來word文檔也是可以解壓縮的,之前一直不知道,通過如下代碼就可以將word文檔解壓縮,並進一步提取內容
var
admZip
=
require('adm-zip');
const
zip
=
new
admZip('test.docx');
//將該docx解壓到指定文件夾result下
zip.extractAllTo("./result",
/*overwrite*/true);
首先我們新建一個docx文檔,內容如下
然後運行上述代碼進行解壓縮,得到如下的文件,由下圖可以看出生成了好幾個文件夾,word的內容其實是在word文件夾里的document.xml文件內(這里解壓縮後其實源文件還在,並沒有消失)
進入word文件夾後的內容
我們繼續打開document.xml文件來一探究竟裡面到底是啥?注意要用瀏覽器直接打開,如果用ide打開顯示出的所有內容都在一行,無法閱讀!
上圖只是word文檔的一部分,會發現word文檔內看著只有幾段文字,但是xml中卻是長篇大論,仔細分析下也很正常,xml全稱可擴展標記語言,其被設計為傳輸和存儲數據,它僅僅是一個純文本的表示,而word中內容格式千變萬化,肯定需要一種方法來有效描述這些內容的格式,因此採用了xml來描述
我們嘗試一下將
測試文檔
四個字加粗變色傾斜字體,如下圖
然後再進行解壓縮,得到docuemnt.xml並查看對應的內容,如下
這就很明顯了,
<w:b/>
表示文字加粗,
<w:i/>
表示文字傾斜,
<w:color>
表示文字的顏色,所以這么4個字就需要這幾行xml來描述,因此長篇大論的xml也就不足為奇
提取內容
上面說到了xml僅僅是一個文本的表示,我們可以用如下代碼讀取整個xml的內容,結果是一個
string
var
contentXml
=
zip.readAsText("word/document.xml");
接下來是重點,如何提取我們想要的內容呢,答案是正則表達式,首先我們得分析一下word文檔的結構,word文檔其實是由叫做
Paragraph
的段落所構成,在vb中可以很輕松的獲取並修改段落,官網傳送門點此
那麼到底怎麼樣才是一個
Paragraph
呢,其實很簡單,仔細觀察word文檔,見到下圖中的小箭頭了么,每個小箭頭前面的內容就是一個段落,那麼下圖中一共有16個
Paragraph
,當然有些段落是空的,沒有任何內容
我們再來研究xml的結構,收起展開的xml,如下圖,發現
<w:p></w:p>
這么個標簽就是表示的一個段落,中間還有些
<w:p>
藏在表格內,這么一看錶格前面3個段落,後面3個段落,和上圖是對應的
因此,
我們就可以提取出每個段落的文本並返回一個數組,每一項就是一個段落的內容
,這樣就能夠完整的解析出整個word的內容,關鍵在於如何提取每個
<w:p>
的內容,我們繼續展開一個
<w:p>
進行觀察,如下圖,發現內容雖多,其實文本都保存在
<w:t>
中間,因此思路就清晰了,
首先用正則表達式提取出所有<w:p>的內容,再針對每個<w:p>的內容,進行進一步正則提取,提取出其裡面所有<w:t>的內容,並拼接在一起構成一個段落的總內容
具體代碼
下面是具體的提取代碼
//參數是word文件名,第二個參數是回調表示解析完成
var
parser
=
function
parseWordDocument(absoluteWordPath,callback){
//返回內容的數組
var
resultList
=
[];
//如果文件存在
fs.exists(absoluteWordPath,
function(exists){
if(exists){
//解壓縮
const
zip
=
new
admZip(absoluteWordPath);
//將document.xml(解壓縮後得到的文件)讀取為text內容
var
contentXml
=
zip.readAsText("word/document.xml");
//正則匹配出對應的<w:p>裡面的內容,方法是先匹配<w:p>,再匹配裡面的<w:t>,將匹配到的加起來即可
//注意?表示非貪婪模式(盡可能少匹配字元),否則只能匹配到一個<w:p></w:p>
var
matchedWP
=
contentXml.match(/<w:p.*?>.*?<\/w:p>/gi);
//繼續匹配每個<w:p></w:p>裡面的<w:t>,這里必須判斷matchedWP存在否則報錯
if(matchedWP){
matchedWP.forEach(function(wpItem){
//注意這里<w:t>的匹配,有可能是<w:t
xml:space="preserve">這種格式,需要特殊處理
var
matchedWT
=
wpItem.match(/(<w:t>.*?<\/w:t>)|(<w:t\s.[^>]*?>.*?<\/w:t>)/gi);
var
textContent
=
'';
if(matchedWT){
matchedWT.forEach(function(wtItem){
//如果不是<w:t
xml:space="preserve">格式
if(wtItem.indexOf('xml:space')===-1){
textContent+=wtItem.slice(5,-6);
}else{
textContent+=wtItem.slice(26,-6);
}
});
resultList.push(textContent)
}
});
//解析完成
callback(resultList)
}
}else{
callback(resultList)
}
});
};
注意一下如果段落前有空格,那麼
<w:t>
的格式是不同的,如下,多了這個space描述,所以需要特殊處理
代碼量其實很少,關鍵在於正則的編寫,上述docx文檔提取後的輸出結果如下
最後我把這個工具寫成了一個npm包,地址點這里
H. nodejs fs.stat 能查看文件夾是否存在么
varfs=require("fs");varstat=fs.lstatSync("./xx");console.log(stat.isDirectory());如果返回結果為true則為文件夾。
I. nodejs如何判斷資料庫操作是否執行完畢
判斷如下:
將運行結果用arr.length來判斷,如果arr.length不像我們期望的那樣,比如由於網路傳輸或者處理異常,少一條,那麼我們將無法做後續的處理。這種處理方式強業務耦合;不具有普適性。taskWatcher 充當非同步任務執行情況的觀察員,僅與非同步過程的調用次數有關,且與其他處理過程無關。方法返回一個 Promise, 它將在上述可迭代對象中的所有 Promise 被 resolve 之後被 resolve,或者在任一 Promise 被 reject 後被 reject。
J. nodejs 判斷key是否存在exists 每次都是true
判斷每次都是true if(rdsclie