Ubuntu + Hadoop 單機偽分佈模式,使用 libhdfs (JNI 封裝) 從 C 程式讀寫 HDFS。編譯命令:
gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/linux \
-I$HADOOP_HOME/include -L$HADOOP_HOME/lib/native \
-lhdfs -o test test.c
現象:./test 拋出 java.io.IOException: Mkdirs failed to create /my。
原因:HDFS 默認用戶 hadoop 無 /my 寫權限。
解決:sudo ./test 或 hdfs dfs -mkdir -p /my && hdfs dfs -chmod 777 /my。生產環境應配置 Kerberos/ACL 而非 sudo。
現象:sudo ./test 提示 Environment variable CLASSPATH not set!。
原因:sudo 默認重置環境變量(env_reset),~/.bashrc 中的 CLASSPATH 不繼承。
解決:
1. sudo -E ./test 保留環境(需 sudoers 允許)。
2. 編輯 /etc/sudoers(用 visudo):Defaults env_keep += "CLASSPATH JAVA_HOME HADOOP_HOME"。
3. 代碼中調用 hdfsBuilderSetConf 顯式指定配置路徑,不依賴環境變量。
操作:chmod 777 /etc/sudoers 後無法 sudo,報錯 mode 0777, should be 0440。
修復:切換 root 用戶修復:
su root → chmod 440 /etc/sudoers → chown root:root /etc/sudoers。
教訓:絕不直接 chmod 系統關鍵文件,務必用 visudo 編輯 sudoers。
JAVA_HOME、HADOOP_HOME、LD_LIBRARY_PATH 包含 libjvm.so 和 libhdfs.so 目錄。hdfsBuilder API 程式化設定 fs.defaultFS、hadoop.conf.dir,避免依賴環境變量。hdfsConnect 返回值,調用 hdfsGetLastError() 獲取詳細 JNI 異常信息。core-site.xml hadoop.proxyuser.*.hosts/groups),生產用 Kerberos + ACL。libhdfs3 (純 C 實現,無 JVM 依賴) 或 WebHDFS REST API (curl + JSON)。#include <hdfs.h>
#include <stdio.h>
int main() {
struct hdfsBuilder *bld = hdfsNewBuilder();
hdfsBuilderSetNameNode(bld, "localhost");
hdfsBuilderSetNameNodePort(bld, 9000);
hdfsFS fs = hdfsBuilderConnect(bld);
if (!fs) { fprintf(stderr, "Connect failed: %s\n", hdfsGetLastError()); return 1; }
hdfsFile f = hdfsOpenFile(fs, "/my/t.txt", O_WRONLY|O_CREAT, 0, 0, 0);
if (!f) { fprintf(stderr, "Open failed: %s\n", hdfsGetLastError()); return 1; }
const char *buf = "Hello HDFS from C!\n";
tSize n = hdfsWrite(fs, f, buf, strlen(buf));
if (n < 0) fprintf(stderr, "Write failed\n");
hdfsCloseFile(fs, f);
hdfsDisconnect(fs);
return 0;
}