vba Workbook.Save 保存到不同目录

vba Workbook.Save saves to different directory

我打开一个现有的 xlsx 文件并添加一个新的工作表。然后我只想保存文件。

Dim wb As Workbook
Dim ws As Worksheet

Set wb = Workbooks.Open(fileName:=pathToFile, Editable:=True, ReadOnly:=False)
Set ws = wb.Worksheets.Add()
ws.Name = "newSheet"
ws.range("A1").CopyFromRecordset rs

wb.Save
wb.Close

但是 wb.Save 将文件保存到 $USERS\Documents,尽管它不是我打开文件的源目录。

知道为什么 vba 这样做吗?

我也试过 wb.SaveAs pathToFile 但这导致了错误。 wb.Close SaveChanges:=True 也不起作用。

我需要将此文件保存到相同的路径和名称。

我当然可以 wb.SaveAs pathToFile & "_tmp",删除旧文件并重命名新文件。但是为什么保存不起作用?

编辑

Dim strCon As String: strCon = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=path\file.xlsx;Mode=Read;Extended Properties=""Excel 12.0;HDR=Yes;IMEX=1"";"
Dim sql as String
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset

Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")

cn.Open strCon
rs.Open Source:=sql, ActiveConnection:=cn

Dim wb As Workbook
Dim ws As Worksheet
Set wb = Workbooks.Open(fileName:=path\file.xlsx, ReadOnly:=False)
Set ws = wb.Worksheets.Add()
ws.Range("A1").CopyFromRecordset rs

rs.Close
cn.Close

wb.Save
wb.Close

经过数小时的尝试和 Oscar 的不懈支持(请参阅评论。非常感谢!),此问题的解决方案是按照 here 中的建议加载工作簿(感谢 Oscar)。尽管如此,工作簿将以只读方式打开。要更改此设置,只需通过设置 wb.ChangeFileAccess xlReadWrite.

更改文件访问模式

上面的代码现在看起来像这样:

Dim strCon As String: strCon = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=path\file.xlsx;Mode=Read;Extended Properties=""Excel 12.0;HDR=Yes;IMEX=1"";"
Dim sql as String
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset

Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")

cn.Open strCon
rs.Open Source:=sql, ActiveConnection:=cn

Dim wb As Workbook
Dim ws As Worksheet
Workbooks.Open Filename:=file.xlsx    ' <-- Look here
Set wb = Workbooks("file.xlsx")       ' <-- And here
Set ws = wb.Worksheets.Add()
ws.Range("A1").CopyFromRecordset rs

rs.Close
cn.Close

wb.ChangeFileAccess xlReadWrite     ' <-- And here
wb.Save
wb.Close

然而,如果省略 wb.ChangeFileAccess xlReadWrite.

,为什么 vba 会将工作簿的路径更改为用户文档目录,这仍然不清楚

编辑

在重构我的代码时,我观察到更多关于 WorkBook.ChangeFileAccess 的使用。如果在同一个 Sub 中创建 ADODB.Connection,您必须像上面描述的那样将文件访问权限更改为 xlReadWrite。但是,如果您编写了一个函数来传递连接字符串和要执行的 sql 查询,然后创建 ADODB 连接,那么更改工作簿的文件访问将导致错误。

示例:

Public Function ExecSql(conn as String, sql as String) As Recordset
    Dim recSet As Recordset
    Dim cn As ADODB.Connection
    Dim rs As ADODB.Recordset

    Set cn = CreateObject("ADODB.Connection")
    cn.Mode = adModeReadWrite
    cn.Open conn

    Set rs = CreateObject("ADODB.Recordset")
    rs.Open Source:=sql, ActiveConnection:=cn

    Set recSet = rs
    Set ExecQuery = recSet
End function

并且在调用子中:

    Dim conn As String: conn = "" ' connection String, see above
    Dim sql As String: sql = ""   ' the query

    ' Open workbook here like above

    Dim rs As Recordset: Set rs = ExecSql(strCon, sql)
    ws.Range("A1").CopyFromRecordset rs

    rs.Close

    ' wb.ChangeFileAccess xlReadWrite     ' not needed
    wb.Save
    wb.Close

不要忘记在调用 sub 而不是在 ExecSql 函数中调用 rs.Close(参见第二和第三个答案 here

另一件事:您必须在打开工作簿后调用 ExecSql。如果之前执行了 ExecSql,它不会保存更改。