通过代码获取文件 tnsnames.ora 的位置

Posted

技术标签:

【中文标题】通过代码获取文件 tnsnames.ora 的位置【英文标题】:Getting location of file tnsnames.ora by code 【发布时间】:2011-01-01 15:35:55 【问题描述】:

如何在安装了 Oracle 客户端的机器上通过代码获取 tnsnames.ora 文件的位置?

是否有指示此文件位置的 Windows 注册表项?

【问题讨论】:

您意识到“以编程方式”意味着“通过代码”,对吧? @George 我正在寻找解决方案,不一定基于 Windows 注册表,因为再次编辑问题。 【参考方案1】:

几年前我也遇到过同样的问题。 那时我必须支持 Oracle 9 和 10,所以代码只处理这些版本,但也许它可以让你免于研究。 这个想法是:

搜索注册表以确定 oracle 客户端版本 尝试查找 ORACLE_HOME 终于从 HOME 获取 tnsnames
public enum OracleVersion

    Oracle9,
    Oracle10,
    Oracle0
;

private OracleVersion GetOracleVersion()

    RegistryKey rgkLM = Registry.LocalMachine;
    RegistryKey rgkAllHome = rgkLM.OpenSubKey(@"SOFTWARE\ORACLE\ALL_HOMES");

    /* 
     * 10g Installationen don't have an ALL_HOMES key
     * Try to find HOME at SOFTWARE\ORACLE\
     * 10g homes start with KEY_
     */
    string[] okeys = rgkLM.OpenSubKey(@"SOFTWARE\ORACLE").GetSubKeyNames();
    foreach (string okey in okeys)
    
        if (okey.StartsWith("KEY_"))
            return OracleVersion.Oracle10;
    

    if (rgkAllHome != null)
    
        string strLastHome = "";
        object objLastHome = rgkAllHome.GetValue("LAST_HOME");
        strLastHome = objLastHome.ToString();
        RegistryKey rgkActualHome = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\ORACLE\HOME" + strLastHome);
        string strOraHome = "";
        object objOraHome = rgkActualHome.GetValue("ORACLE_HOME");
        string strOracleHome = strOraHome = objOraHome.ToString();
        return OracleVersion.Oracle9;
    
    return OracleVersion.Oracle0;


private string GetOracleHome()

    RegistryKey rgkLM = Registry.LocalMachine;
    RegistryKey rgkAllHome = rgkLM.OpenSubKey(@"SOFTWARE\ORACLE\ALL_HOMES");
    OracleVersion ov = this.GetOracleVersion();

    switch(ov)
    
        case OracleVersion.Oracle10:
            
                string[] okeys = rgkLM.OpenSubKey(@"SOFTWARE\ORACLE").GetSubKeyNames();
                foreach (string okey in okeys)
                
                    if (okey.StartsWith("KEY_"))
                    
                        return rgkLM.OpenSubKey(@"SOFTWARE\ORACLE\" + okey).GetValue("ORACLE_HOME") as string;
                    
                
                throw new Exception("No Oracle Home found");
            
        case OracleVersion.Oracle9:
            
                string strLastHome = "";
                object objLastHome = rgkAllHome.GetValue("LAST_HOME");
                strLastHome = objLastHome.ToString();
                RegistryKey rgkActualHome = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\ORACLE\HOME" + strLastHome);
                string strOraHome = "";
                object objOraHome = rgkActualHome.GetValue("ORACLE_HOME");
                string strOracleHome = strOraHome = objOraHome.ToString();
                return strOraHome;
            
        default:
            
                throw new Exception("No supported Oracle Installation found");
            
    


public string GetTNSNAMESORAFilePath()

    string strOracleHome = GetOracleHome();
    if (strOracleHome != "")
    
        string strTNSNAMESORAFilePath = strOracleHome + @"\NETWORK\ADMIN\TNSNAMES.ORA";
        if (File.Exists(strTNSNAMESORAFilePath))
        
            return strTNSNAMESORAFilePath;
        
        else
        
            strTNSNAMESORAFilePath = strOracleHome + @"\NET80\ADMIN\TNSNAMES.ORA";
            if (File.Exists(strTNSNAMESORAFilePath))
            
                return strTNSNAMESORAFilePath;
            
            else
            
                throw new SystemException("Could not find tnsnames.ora");
            
        
    
    else
    
        throw new SystemException("Could not determine ORAHOME");
    

【讨论】:

+1 看起来是一个合理的起点。当然,满足非标准安装和各种解析选项以及 Instant Client 之类的功能可能会让您白发苍苍。 您应该尝试在 GetOracleHome() 中的注册表之前使用环境变量。 谢天谢地,我不再需要赶上 Oracle,因为其他人现在正在维护此代码 :) 但是在查询注册表之前检查环境听起来不错。【参考方案2】:

在 Windows 上,最可能的位置是 %ORACLE_HOME%/network/admin%TNS_ADMIN%(或 TNS_ADMIN 注册表设置)。这两个几乎涵盖了所有安装。

当然,没有这个文件也可以有一个正常工作的 Oracle 客户端。 Oracle 有一系列令人眼花缭乱的网络选项,并且有很多方法可以使用 TNSNAMES 来实现工作设置。根据您在此处尝试实现的目标,您的第一个调用端口可能是sqlnet.ora 文件,该文件也在%ORACLE_HOME%/network/admin 中找到。这应该包含如下所示的一行:

NAMES.DIRECTORY_PATH= (LDAP, TNSNAMES, HOSTNAME)

TNSNAMES 表示它将使用TNSNAMES.ora 文件(在本例中为第二个)。 LDAPHOSTNAME 是解析数据库的替代方法。如果没有TNSNAMES,如果TNSNAMES.ora 文件存在于正确的位置,它将被忽略。

在 C#/.NET 中,这应该会为您提供环境变量:

Environment.GetEnvironmentVariable("ORACLE_HOME");

Environment.GetEnvironmentVariable("TNS_ADMIN");

【讨论】:

@Colin,不幸的是,这些变量并不总是由 oracle 客户端设置。我正在使用 oracle 11g。 您使用的是即时客户端还是普通客户端? 我相信 Instant Client 默认不会创建 %ORACLE_HOME% 或 tnsnames.ora 在 Windows 下你必须查看注册表 HKLM\Software\Oracle - 你会在那里找到 oracle home 路径,请注意可能有多个 oracle home,Oracle 允许安装多个每个版本都在自己的家中。【参考方案3】:
List<string> logicalDrives = Directory.GetLogicalDrives().ToList();
            List<string> result = new List<string>();
            foreach (string drive in logicalDrives)
            
                Console.WriteLine("Searching " + drive);
                DriveInfo di = new DriveInfo(drive);
                if(di.IsReady)
                    result = Directory.GetFiles(drive, "tnsnames.ora", SearchOption.AllDirectories).ToList();
                if (0 < result.Count) return;
            
            foreach (string file in result)  Console.WriteLine(result); 

【讨论】:

这列出了 tnsnames.ora 的 每个 副本。它不显示正在使用哪个。 不是我的问题,但你是对的,不清楚。在实践中,确定正在使用的 tnsnames.ora 通常很重要,但我认为您的回答仍然是一个有用的贡献,加上我添加的警告,所以我给了您一个赞成票来反对您收到的反对票。【参考方案4】:

根据网上的说法,取决于Oracle的版本和SQL*Plus进程的工作目录。 This first link 告诉您指定 Oracle 某些版本(7、8、9i)的基本路径的环境变量。如果你使用不同的,我相信有类似的方法可以进入系统目录。

如果您将这些文件的版本分布在各处,并依赖客户端的“首先查找本地 tnsnames.ora”行为,那么我猜您不走运。

【讨论】:

该链接有些过时了,但在最新版本 (11g) 之前的行为大致相同。【参考方案5】:

就此而言,我不是 C# 或 Windows 专家,因此希望这会有所帮助。 tnsnames.ora 文件应位于:

ORACLE_HOME\network\admin

如果指定了备用位置,则应该可以通过 TNS_ADMIN 注册表项访问它。

有关 Oracle 如何在 Windows 上处理 tns 名称的更多信息,请参阅link。

【讨论】:

以上是关于通过代码获取文件 tnsnames.ora 的位置的主要内容,如果未能解决你的问题,请参考以下文章

PlSql链接Oracle数据库对tnsnames.ora文件的配置

ORACLE配置,修改tnsnames.ora文件实例

Oracle的tnsnames.ora配置(PLSQL Developer)

ODAC的tnsnames.ora文件

Oracle Database 19c 不可用 tnsnames.ora 文件

Oracle三个配置文件tnsnames-listener-sqlnet介绍