中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS批处理 & 脚本技术(批处理室) » 求助:vbs把xls文件转换为txt文件
作者:
标题: 求助:vbs把xls文件转换为txt文件 上一主题 | 下一主题
26933062
银牌会员





积分 2268
发帖 879
注册 2006-12-19
状态 离线
『楼 主』:  求助:vbs把xls文件转换为txt文件

求助:vbs把xls文件转换为txt文件
要求:
   xzt.vbs 运行方式是从bat中调用 如: call xzt.vbs "a.xls" "hhh.txt"
vbs功能
1、首先把xls文件中的所有空值改为#
2、再把xls文件另存为hhh.txt
注:要求1中把所有空值改为#并不是要改xls文件内容,目的是要txt中的空值等于#
    如果要求1有难度,可以忽略,直接解决第2个要求也可以。
        表中有些单元格的数据是通过公式计算出来的结果,要求在txt中直接显示结果

补充说明:
不确定有几张表
是从 A1到有值的最大区域
但头三行有合并的单元格,如果不确定头几行含合并单元格有影响吗?
如果有影响都定死为头三行含合并单元格.       
有劳大家!

[ Last edited by 26933062 on 2010-1-5 at 17:24 ]



致精致简!
2010-1-5 12:59
查看资料  发短消息 网志   编辑帖子  回复  引用回复
qinchun36
高级用户

据说是李先生


积分 609
发帖 400
注册 2008-4-23
状态 离线
『第 2 楼』:  

哈,我正在弄一个为命令行界面服务的VBS,嘿嘿。。。

你给出的条件不完善:

1. 是否这个xls只有一张表,即只有 Sheet1 ?

2. 需要导出的范围多大?
    是从 A1到有值的最大区域,还是只是能包含所有数据的最小区域,因为不排除有人前面空上很多行再写。



┏━━━━━━┓
┃据说是李先生┃
┠──────┨
┃*ntRSS┃
┗━━━━━━┛
2010-1-5 15:45
查看资料  发送邮件  发短消息 网志  OICQ (182484135)  编辑帖子  回复  引用回复
26933062
银牌会员





积分 2268
发帖 879
注册 2006-12-19
状态 离线
『第 3 楼』:  回复2楼

不确定有几张表
是从 A1到有值的最大区域
但头三行有合并的单元格,如果不确定头几行含合并单元格有影响吗?
谢谢!

[ Last edited by 26933062 on 2010-1-5 at 17:22 ]



致精致简!
2010-1-5 17:20
查看资料  发短消息 网志   编辑帖子  回复  引用回复
qinchun36
高级用户

据说是李先生


积分 609
发帖 400
注册 2008-4-23
状态 离线
『第 4 楼』:  

不能解决的问题:

1. 不能按照你给的方案命名导出的文件,因为不确定有几张表,你在命令行无法给出参数;
  我把你的第二个参数改成指定导出路径,文本文件的命名是 "输出路径\EXCEL文件名.表名.txt"

2. 经试验发现,合并的单元格被识别成 最左上的单元格包含所有数据,其他单元格数据为空。

另:
不给输出路径则默认当前工作路径;
默认不导出空的表,如果有特殊需求可以修改 VBS 源代码里面的那个参数,有说明。
'***************************************************
'*
'*  特殊需求的EXCEL导出文本工具 xzt.vbs
'*
'*   (P)&(C) 2010  『据说是李先生』
'*       qinchun36   CN-DOS.net
'*
'*  xzt.vbs EXCEL文件名 [输出路径]
'*  xzt.vbs [drive:][path]filename [drive:][path]
'*
'*  输出文件为  输出路径\EXCEL文件名.表名.txt
'*
'***************************************************
On Error Resume Next

Set fso = WScript.Createobject("Scripting.FileSystemObject")

' 获取文件的全路径,因为 EXCEL 需要全路径
fileInputName  = WScript.Arguments(0)
fileFullName = fso.GetFile(fileInputName).Path

' 如果未指定输出路径则默认为当前工作路径;
' 如果指定的路径不纯在则尝试创建,但仅在它的父目录存在时能成功
fileOutputFolder = fso.GetFolder(".").Path
If WScript.Arguments.Count > 1 Then
        fileOutputFolder = WScript.Arguments(1)
        If Not fso.FolderExists(fileOutputFolder) Then fso.CreateFolder fileOutputFolder
End If

'fileOutputFolder = fso.GetFile(fileInputName).ParentFolder
' 输出文件路径,经过我考虑决定去掉,因为你不知道有几张表。
'fileOutputName = WScript.Arguments(1)
'Set f = fso.CreateTextFile(fileOutputName, True, True)

' 创建 Excel.Application 对象
Set excel = WScript.CreateObject("Excel.Application")

'===============================================
' 上面把所有必需的“基础设施”都搞一遍,
' 每个都是致命的,因此累积错误,如果有的话就退出
'===============================================
If Err.Number <> 0 Then
        WScript.Echo "因参数错误或没安装EXCEL,程序退出:" & vbCrLf & vbCrLf & Err.Description
        Err.Clear
        excel.Quit
        WScript.Quit
End If

' “打开EXCEL程序”
Set wbs = excel.Application.Workbooks
' 打开一个 EXCEL 文件
wbs.Open(fileFullName)
' 得到这个文件
Set wb = wbs.Item(1)
' 得到所有的表
Set shts = wb.Sheets
' 初始化提示信息
msg = "处理的文件是" & vbCrLf & fileFullName & vbCrLf & vbCrLf & "共有 " & shts.Count & " 张表,分别导出为" & vbCrLf
' 干活, False 表示不导出空的表
DealWithAllSheets shts, False
' 退出
wb.Close
wbs.Close
excel.Quit
MsgBox msg, 4160, "完成"
WScript.Quit

'******************************** 下面都是功能函数了 ****************************************

' 获取一张工作表已经使用的数据范围相关信息
' 返回数组 {已使用行数, 已使用列数, 最小行号, 最大行号, 最小列号, 最大列号}
'         WorksheetObject.UsedRange 是此工作表已经使用的区域
'        .Rows 是它所有的行,.Columns是所有的列
'        .Count 是总数,.Row 是行号,.Column 是列号
'-----------------------------------------------
Function GetUsedRangeXY(WorksheetObject)
        Dim x, y, x0, x1, y0, y1
        y = WorksheetObject.UsedRange.Rows.Count
        If y = 0 Then
                y0 = 0
                y1 = 0
        Else
                y0 = WorksheetObject.UsedRange.Rows(1).Row
                For Each rw In WorksheetObject.UsedRange.Rows
                        y1 = rw.Row
                Next
        End If
        x = WorksheetObject.UsedRange.Columns.Count
        If x = 0 Then
                x0 = 0
                x1 = 0
        Else
                x0 = WorksheetObject.UsedRange.Columns(1).Column
                For Each col In WorksheetObject.UsedRange.Columns
                        x1 = col.Column
                Next
        End If
        GetUsedRangeXY = Array(y, x, y0, y1, x0, x1)
End Function


' 遍历并处理每张表
' 参数 allSheets 是一个 WorkSheets 对象
' bOutputNullSheet 控制是否输出空的表单
'    True 为输出,False 为不输出
'-------------------------------------------------
Sub DealWithAllSheets(allSheets, bOutputNullSheet)
        Dim oneSheet()
        For Each sht in allSheets
                msg = msg & vbCrLf & sht.Name & " ==> "
                ' 一张表的信息
                temp = GetUsedRangeXY(sht)
                ix = temp(3) - 1
                iy = temp(5) - 1
                ' 装一个表的数据
                ReDim oneSheet(ix, iy)
                ' 所有的表格
                Set cls = sht.Cells
                For i = 0 To ix
                        For j = 0 To iy
                                val = cls((i + 1), (j + 1)).Value
                                If val = "" Then val = "#"
                                oneSheet(i,j) = val
                        Next
                Next
                If ix + iy > 0 Or bOutputNullSheet Then
                        OutPutOneSheet oneSheet, sht.Name
                Else
                        msg = msg & "是空的,未导出。" & vbCrLf
                End If
        Next
End Sub


' 比较整洁地输出一张表的内容
'---------------------------
Sub OutPutOneSheet(Arraymxn, sheetName)
        ' 这里使用 Unicode 编码输出,以保持最大兼容性
        ' 你也可以将第三个参数 True 改成 False 或者去掉以使用 ASCII 编码
        Set f = fso.CreateTextFile(fileOutputFolder & "\" & wb.Name & "." & sheetName & ".txt", True, True)
        For j = 0 To UBound(Arraymxn, 2)
                l = 0
                For i = 0 To UBound(Arraymxn, 1)
                        li = getLenInTabs(Arraymxn(i, j))
                        If li > l Then l = li
                Next
                For i = 0 To UBound(Arraymxn, 1)
                        lx = l - getLenInTabs(Arraymxn(i, j))
                        For k = 0 To lx
                                Arraymxn(i, j) = Arraymxn(i, j) & vbTab
                        Next
                Next
        Next
        For i = 0 To UBound(Arraymxn, 1)
                For j = 0 To UBound(Arraymxn, 2)
                        f.Write Arraymxn(i, j)
                Next
                f.Write vbCrLf
        Next
        f.Close
        msg = msg & fso.GetFile(fileOutputFolder & "\" & wb.Name & "." & sheetName & ".txt").Path & vbCrLf
End Sub

' 粗略得到一个字符串看起来的长度(上限)占用的最小的制表符个数
'------------------------------
Function getLenInTabs(sString)
        Dim str, ch, l
        str = sString
        l = Len(str)
        While Len(str) > 0
                ch = Left(str, 1)
                If AscW(ch) > 255 Or AscW(ch) < 0 Then l = l + 1
                str = Mid(str, 2)
        WEnd
        l = (Int)(l / 8) + 1
        getLenInTabs = l
End Function




┏━━━━━━┓
┃据说是李先生┃
┠──────┨
┃*ntRSS┃
┗━━━━━━┛
2010-1-6 10:24
查看资料  发送邮件  发短消息 网志  OICQ (182484135)  编辑帖子  回复  引用回复
26933062
银牌会员





积分 2268
发帖 879
注册 2006-12-19
状态 离线
『第 5 楼』:  

谢谢你的帮助,已在批处理之家找到答案,http://bathome.l3.wuyou.com/thread-6921-1-1.html
再次感谢,我会测试你的代码的。



致精致简!
2010-1-6 19:43
查看资料  发短消息 网志   编辑帖子  回复  引用回复
mountvol
初级用户





积分 186
发帖 117
注册 2006-8-14
状态 离线
『第 6 楼』:  

用ado来操作excel最适合,直接可以getstring然后保存为文本就可以了。
而且还可以遍历表名.

2010-1-6 21:03
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
moniuming
银牌会员

永远的菜鸟



积分 1335
发帖 574
注册 2007-11-27
来自 广西
状态 离线
『第 7 楼』:  

其实在excel中通过vba来操作会更容易些...

2010-1-6 22:37
查看资料  发短消息 网志   编辑帖子  回复  引用回复
qinchun36
高级用户

据说是李先生


积分 609
发帖 400
注册 2008-4-23
状态 离线
『第 8 楼』:  

Re: 5   哇,原来是马甲!

Re: 6  个人认为还是微软自己提供的专门操作EXCEL的对象好用,你说的变量表名之类都只是它方法的一小部分,你可以尝试运行一下这个代码,最后提示就可以看出是经过遍历所有表名出来的结果。

Re: 7  我没有试过,但是觉得VBA看起来语法太严格,不喜欢

其实要读出数据很简单,几个循环就行了,可是我对输出的样子好不好看比较在意,所有多加了些代码,可能看起来很繁琐把,个人爱好不同。



┏━━━━━━┓
┃据说是李先生┃
┠──────┨
┃*ntRSS┃
┗━━━━━━┛
2010-1-7 09:38
查看资料  发送邮件  发短消息 网志  OICQ (182484135)  编辑帖子  回复  引用回复
mountvol
初级用户





积分 186
发帖 117
注册 2006-8-14
状态 离线
『第 9 楼』:  

很明显,并不是所有的windows上都装有excel,所以Excel.Application其实很多时候并不能被创建。
另外,vba比vbs强大(因为它可以用API),在vbs中可以通过操作OFFICE来使用vba,从而实现调用API.

2010-1-7 20:17
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
bat-zw
金牌会员

永远的学习者


积分 3105
发帖 1276
注册 2008-3-8
状态 离线
『第 10 楼』:  我来跟一贴


'另存工作表为txt文件,并将空值替换为#
dim hang,lie,counter,counter1,vbstr '声明变量
on error resume next '忽略错误

'设置对象
set wshshell=createobject ("wscript.shell")
path=wshshell.currentdirectory '当前路径
set objexcel=createobject ("excel.application")
set objworks=objexcel.workbooks.open (path&"\"&wscript.arguments(0))
set objfso=createobject("scripting.filesystemobject")
set objtext=objfso.opentextfile(path&"\"&wscript.arguments(1),2,true)
objexcel.worksheets(1).activate

'从第四行开始获取工作表有效总行列数(舍弃前三行非数据行)
counter=0
do
     counter=counter+1
loop until objexcel.cells(4,counter).value=""
lie=counter-1:counter=3
do
     counter=counter+1
loop until objexcel.cells(counter,1).value=""
hang=counter-1:counter=0

'读取工作表数据并将空值替换为#
for counter=4 to hang
    for counter1=1 to lie
        vbstr=objexcel.cells(counter,counter1).value
        if vbstr="" then
           strexcel=strexcel&" #"
           else
           if replace(vbstr,".","")<>vbstr then vbstr=round(vbstr,2) '对小数取两位小数并四舍五入
           if mid(vbstr,1,1)="." then vbstr="0"&vbstr
           strexcel=strexcel&" "&vbstr
        end if
     next
     strexcel=strexcel&vbcrlf
next
objtext.write strexcel
objtext.close
objworks.close

'清空对象,释放内存
set objtext=nothing
set objfso=nothing
set objworks=nothing
set objexcel=nothing
set wshshell=nothing




批处理之家新域名:www.bathome.net
2010-1-7 20:57
查看资料  发送邮件  发短消息 网志  OICQ (841615149)  编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: