zoukankan      html  css  js  c++  java
  • JAVA通过oshi获取系统和硬件信息

    一、引入jar包

      本项目主要使用第开源jar包:https://github.com/oshi/oshi

            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>RELEASE</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/com.github.oshi/oshi-core -->
            <dependency>
                <groupId>com.github.oshi</groupId>
                <artifactId>oshi-core</artifactId>
                <version>3.5.0</version>
            </dependency>

    二、测试代码 

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import oshi.SystemInfo;
    import oshi.hardware.*;
    import oshi.hardware.CentralProcessor.TickType;
    import oshi.software.os.*;
    import oshi.software.os.OperatingSystem.ProcessSort;
    import oshi.util.FormatUtil;
    import oshi.util.Util;
    
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * The Class SystemInfoTest.
     *
     * @author dblock[at]dblock[dot]org
     */
    public class SystemInfoTest {
    
        /**
         * The main method.
         *
         * @param args the arguments
         */
        public static void main(String[] args) {
            // Options: ERROR > WARN > INFO > DEBUG > TRACE
            Logger LOG = LoggerFactory.getLogger(SystemInfoTest.class);
    
            LOG.info("Initializing System...");
            SystemInfo si = new SystemInfo();
    
            HardwareAbstractionLayer hal = si.getHardware();
            OperatingSystem os = si.getOperatingSystem();
    
            System.out.println(os);
    
            LOG.info("Checking computer system...");
            printComputerSystem(hal.getComputerSystem());
    
            LOG.info("Checking Processor...");
            printProcessor(hal.getProcessor());
    
            LOG.info("Checking Memory...");
            printMemory(hal.getMemory());
    
            LOG.info("Checking CPU...");
            printCpu(hal.getProcessor());
    
            LOG.info("Checking Processes...");
            printProcesses(os, hal.getMemory());
    
            LOG.info("Checking Sensors...");
            printSensors(hal.getSensors());
    
            LOG.info("Checking Power sources...");
            printPowerSources(hal.getPowerSources());
    
            LOG.info("Checking Disks...");
            printDisks(hal.getDiskStores());
    
            LOG.info("Checking File System...");
            printFileSystem(os.getFileSystem());
    
            LOG.info("Checking Network interfaces...");
            printNetworkInterfaces(hal.getNetworkIFs());
    
            LOG.info("Checking Network parameterss...");
            printNetworkParameters(os.getNetworkParams());
    
            // hardware: displays
            LOG.info("Checking Displays...");
            printDisplays(hal.getDisplays());
    
            // hardware: USB devices
            LOG.info("Checking USB Devices...");
            printUsbDevices(hal.getUsbDevices(true));
        }
    
        private static void printComputerSystem(final ComputerSystem computerSystem) {
    
            System.out.println("manufacturer: " + computerSystem.getManufacturer());
            System.out.println("model: " + computerSystem.getModel());
            System.out.println("serialnumber: " + computerSystem.getSerialNumber());
            final Firmware firmware = computerSystem.getFirmware();
            System.out.println("firmware:");
            System.out.println("  manufacturer: " + firmware.getManufacturer());
            System.out.println("  name: " + firmware.getName());
            System.out.println("  description: " + firmware.getDescription());
            System.out.println("  version: " + firmware.getVersion());
            System.out.println("  release date: " + (firmware.getReleaseDate() == null ? "unknown"
                    : firmware.getReleaseDate() == null ? "unknown" : FormatUtil.formatDate(firmware.getReleaseDate())));
            final Baseboard baseboard = computerSystem.getBaseboard();
            System.out.println("baseboard:");
            System.out.println("  manufacturer: " + baseboard.getManufacturer());
            System.out.println("  model: " + baseboard.getModel());
            System.out.println("  version: " + baseboard.getVersion());
            System.out.println("  serialnumber: " + baseboard.getSerialNumber());
        }
    
        private static void printProcessor(CentralProcessor processor) {
            System.out.println(processor);
            System.out.println(" " + processor.getPhysicalPackageCount() + " physical CPU package(s)");
            System.out.println(" " + processor.getPhysicalProcessorCount() + " physical CPU core(s)");
            System.out.println(" " + processor.getLogicalProcessorCount() + " logical CPU(s)");
    
            System.out.println("Identifier: " + processor.getIdentifier());
            System.out.println("ProcessorID: " + processor.getProcessorID());
        }
    
        private static void printMemory(GlobalMemory memory) {
            System.out.println("Memory: " + FormatUtil.formatBytes(memory.getAvailable()) + "/"
                    + FormatUtil.formatBytes(memory.getTotal()));
            System.out.println("Swap used: " + FormatUtil.formatBytes(memory.getSwapUsed()) + "/"
                    + FormatUtil.formatBytes(memory.getSwapTotal()));
        }
    
        private static void printCpu(CentralProcessor processor) {
            System.out.println("Uptime: " + FormatUtil.formatElapsedSecs(processor.getSystemUptime()));
            System.out.println(
                    "Context Switches/Interrupts: " + processor.getContextSwitches() + " / " + processor.getInterrupts());
    
            long[] prevTicks = processor.getSystemCpuLoadTicks();
            System.out.println("CPU, IOWait, and IRQ ticks @ 0 sec:" + Arrays.toString(prevTicks));
            // Wait a second...
            Util.sleep(1000);
            long[] ticks = processor.getSystemCpuLoadTicks();
            System.out.println("CPU, IOWait, and IRQ ticks @ 1 sec:" + Arrays.toString(ticks));
            long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
            long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
            long sys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
            long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
            long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
            long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
            long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
            long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
            long totalCpu = user + nice + sys + idle + iowait + irq + softirq + steal;
    
            System.out.format(
                    "User: %.1f%% Nice: %.1f%% System: %.1f%% Idle: %.1f%% IOwait: %.1f%% IRQ: %.1f%% SoftIRQ: %.1f%% Steal: %.1f%%%n",
                    100d * user / totalCpu, 100d * nice / totalCpu, 100d * sys / totalCpu, 100d * idle / totalCpu,
                    100d * iowait / totalCpu, 100d * irq / totalCpu, 100d * softirq / totalCpu, 100d * steal / totalCpu);
            System.out.format("CPU load: %.1f%% (counting ticks)%n", processor.getSystemCpuLoadBetweenTicks() * 100);
            System.out.format("CPU load: %.1f%% (OS MXBean)%n", processor.getSystemCpuLoad() * 100);
            double[] loadAverage = processor.getSystemLoadAverage(3);
            System.out.println("CPU load averages:" + (loadAverage[0] < 0 ? " N/A" : String.format(" %.2f", loadAverage[0]))
                    + (loadAverage[1] < 0 ? " N/A" : String.format(" %.2f", loadAverage[1]))
                    + (loadAverage[2] < 0 ? " N/A" : String.format(" %.2f", loadAverage[2])));
            // per core CPU
            StringBuilder procCpu = new StringBuilder("CPU load per processor:");
            double[] load = processor.getProcessorCpuLoadBetweenTicks();
            for (double avg : load) {
                procCpu.append(String.format(" %.1f%%", avg * 100));
            }
            System.out.println(procCpu.toString());
        }
    
        private static void printProcesses(OperatingSystem os, GlobalMemory memory) {
            System.out.println("Processes: " + os.getProcessCount() + ", Threads: " + os.getThreadCount());
            // Sort by highest CPU
            List<OSProcess> procs = Arrays.asList(os.getProcesses(5, ProcessSort.CPU));
    
            System.out.println("   PID  %CPU %MEM       VSZ       RSS Name");
            for (int i = 0; i < procs.size() && i < 5; i++) {
                OSProcess p = procs.get(i);
                System.out.format(" %5d %5.1f %4.1f %9s %9s %s%n", p.getProcessID(),
                        100d * (p.getKernelTime() + p.getUserTime()) / p.getUpTime(),
                        100d * p.getResidentSetSize() / memory.getTotal(), FormatUtil.formatBytes(p.getVirtualSize()),
                        FormatUtil.formatBytes(p.getResidentSetSize()), p.getName());
            }
        }
    
        private static void printSensors(Sensors sensors) {
            System.out.println("Sensors:");
            System.out.format(" CPU Temperature: %.1f°C%n", sensors.getCpuTemperature());
            System.out.println(" Fan Speeds: " + Arrays.toString(sensors.getFanSpeeds()));
            System.out.format(" CPU Voltage: %.1fV%n", sensors.getCpuVoltage());
        }
    
        private static void printPowerSources(PowerSource[] powerSources) {
            StringBuilder sb = new StringBuilder("Power: ");
            if (powerSources.length == 0) {
                sb.append("Unknown");
            } else {
                double timeRemaining = powerSources[0].getTimeRemaining();
                if (timeRemaining < -1d) {
                    sb.append("Charging");
                } else if (timeRemaining < 0d) {
                    sb.append("Calculating time remaining");
                } else {
                    sb.append(String.format("%d:%02d remaining", (int) (timeRemaining / 3600),
                            (int) (timeRemaining / 60) % 60));
                }
            }
            for (PowerSource pSource : powerSources) {
                sb.append(String.format("%n %s @ %.1f%%", pSource.getName(), pSource.getRemainingCapacity() * 100d));
            }
            System.out.println(sb.toString());
        }
    
        private static void printDisks(HWDiskStore[] diskStores) {
            System.out.println("Disks:");
            for (HWDiskStore disk : diskStores) {
                boolean readwrite = disk.getReads() > 0 || disk.getWrites() > 0;
                System.out.format(" %s: (model: %s - S/N: %s) size: %s, reads: %s (%s), writes: %s (%s), xfer: %s ms%n",
                        disk.getName(), disk.getModel(), disk.getSerial(),
                        disk.getSize() > 0 ? FormatUtil.formatBytesDecimal(disk.getSize()) : "?",
                        readwrite ? disk.getReads() : "?", readwrite ? FormatUtil.formatBytes(disk.getReadBytes()) : "?",
                        readwrite ? disk.getWrites() : "?", readwrite ? FormatUtil.formatBytes(disk.getWriteBytes()) : "?",
                        readwrite ? disk.getTransferTime() : "?");
                HWPartition[] partitions = disk.getPartitions();
                if (partitions == null) {
                    // TODO Remove when all OS's implemented
                    continue;
                }
                for (HWPartition part : partitions) {
                    System.out.format(" |-- %s: %s (%s) Maj:Min=%d:%d, size: %s%s%n", part.getIdentification(),
                            part.getName(), part.getType(), part.getMajor(), part.getMinor(),
                            FormatUtil.formatBytesDecimal(part.getSize()),
                            part.getMountPoint().isEmpty() ? "" : " @ " + part.getMountPoint());
                }
            }
        }
    
        private static void printFileSystem(FileSystem fileSystem) {
            System.out.println("File System:");
    
            System.out.format(" File Descriptors: %d/%d%n", fileSystem.getOpenFileDescriptors(),
                    fileSystem.getMaxFileDescriptors());
    
            OSFileStore[] fsArray = fileSystem.getFileStores();
            for (OSFileStore fs : fsArray) {
                long usable = fs.getUsableSpace();
                long total = fs.getTotalSpace();
                System.out.format(
                        " %s (%s) [%s] %s of %s free (%.1f%%) is %s "
                                + (fs.getLogicalVolume() != null && fs.getLogicalVolume().length() > 0 ? "[%s]" : "%s")
                                + " and is mounted at %s%n",
                        fs.getName(), fs.getDescription().isEmpty() ? "file system" : fs.getDescription(), fs.getType(),
                        FormatUtil.formatBytes(usable), FormatUtil.formatBytes(fs.getTotalSpace()), 100d * usable / total,
                        fs.getVolume(), fs.getLogicalVolume(), fs.getMount());
            }
        }
    
        private static void printNetworkInterfaces(NetworkIF[] networkIFs) {
            System.out.println("Network interfaces:");
            for (NetworkIF net : networkIFs) {
                System.out.format(" Name: %s (%s)%n", net.getName(), net.getDisplayName());
                System.out.format("   MAC Address: %s %n", net.getMacaddr());
                System.out.format("   MTU: %s, Speed: %s %n", net.getMTU(), FormatUtil.formatValue(net.getSpeed(), "bps"));
                System.out.format("   IPv4: %s %n", Arrays.toString(net.getIPv4addr()));
                System.out.format("   IPv6: %s %n", Arrays.toString(net.getIPv6addr()));
                boolean hasData = net.getBytesRecv() > 0 || net.getBytesSent() > 0 || net.getPacketsRecv() > 0
                        || net.getPacketsSent() > 0;
                System.out.format("   Traffic: received %s/%s%s; transmitted %s/%s%s %n",
                        hasData ? net.getPacketsRecv() + " packets" : "?",
                        hasData ? FormatUtil.formatBytes(net.getBytesRecv()) : "?",
                        hasData ? " (" + net.getInErrors() + " err)" : "",
                        hasData ? net.getPacketsSent() + " packets" : "?",
                        hasData ? FormatUtil.formatBytes(net.getBytesSent()) : "?",
                        hasData ? " (" + net.getOutErrors() + " err)" : "");
            }
        }
    
        private static void printNetworkParameters(NetworkParams networkParams) {
            System.out.println("Network parameters:");
            System.out.format(" Host name: %s%n", networkParams.getHostName());
            System.out.format(" Domain name: %s%n", networkParams.getDomainName());
            System.out.format(" DNS servers: %s%n", Arrays.toString(networkParams.getDnsServers()));
            System.out.format(" IPv4 Gateway: %s%n", networkParams.getIpv4DefaultGateway());
            System.out.format(" IPv6 Gateway: %s%n", networkParams.getIpv6DefaultGateway());
        }
    
        private static void printDisplays(Display[] displays) {
            System.out.println("Displays:");
            int i = 0;
            for (Display display : displays) {
                System.out.println(" Display " + i + ":");
                System.out.println(display.toString());
                i++;
            }
        }
    
        private static void printUsbDevices(UsbDevice[] usbDevices) {
            System.out.println("USB Devices:");
            for (UsbDevice usbDevice : usbDevices) {
                System.out.println(usbDevice.toString());
            }
        }
    }

    三、结果

    Microsoft Windows 10 build 15063
    manufacturer: LENOVO
    model: 80RU
    serialnumber: R90LN08UR9N0B6922009
    firmware:
      manufacturer: LENOVO
      name: E5CN53WW
      description: E5CN53WW
      version: LENOVO - 0
      release date: 07/11/2016
    baseboard:
      manufacturer: LENOVO
      model: unknown
      version: SDK0K09938 WIN
      serialnumber: R90LN08U
    Intel(R) Core(TM) i5-6300HQ CPU @ 2.30GHz
     1 physical CPU package(s)
     4 physical CPU core(s)
     4 logical CPU(s)
    Identifier: Intel64 Family 6 Model 94 Stepping 3
    ProcessorID: BFEBFBFF000506E3
    Memory: 1.5 GiB/7.8 GiB
    Swap used: 84.4 MiB/6.3 GiB
    Uptime: 1 days, 11:45:25
    Context Switches/Interrupts: 648525190 / 338012494
    CPU, IOWait, and IRQ ticks @ 0 sec:[18421421, 0, 10068431, 288934828, 0, 266351, 143296, 0]
    CPU, IOWait, and IRQ ticks @ 1 sec:[18421578, 0, 10068486, 288938671, 0, 266351, 143304, 0]
    User: 3.9% Nice: 0.0% System: 1.4% Idle: 94.6% IOwait: 0.0% IRQ: 0.0% SoftIRQ: 0.2% Steal: 0.0%
    CPU load: 13.0% (counting ticks)
    CPU load: 17.4% (OS MXBean)
    CPU load averages: N/A N/A N/A
    CPU load per processor: 19.3% 12.8% 12.8% 12.8%
    Processes: 184, Threads: 2447
       PID  %CPU %MEM       VSZ       RSS Name
         0 100.0  0.0    64 KiB     8 KiB System Idle Process
      5416  10.0  1.6   3.4 GiB 130.4 MiB java.exe
     12676   8.8  1.3   2.1 GiB 104.9 MiB java.exe
     11988   5.8 16.8   3.3 GiB   1.3 GiB idea64.exe
      5312   4.4  1.3   2.0 TiB 101.4 MiB chrome.exe
    Sensors:
     CPU Temperature: 42.0°C
     Fan Speeds: [0]
     CPU Voltage: 0.0V
    Power: Charging
     System Battery @ 96.6%
    Disks:
     \.PHYSICALDRIVE0: (model: SanDisk SD7SN6S128G (标准磁盘驱动器) - S/N: 161416401094) size: 128.0 GB, reads: 1117123 (33.4 GiB), writes: 703948 (21.2 GiB), xfer: 2570354 ms
     |-- 磁盘 #0,分区 #0: GPT: Basic Data (GPT: 基本数据) Maj:Min=0:0, size: 471.9 MB @ F:
     |-- 磁盘 #0,分区 #1: GPT: System (GPT: 系统) Maj:Min=0:1, size: 104.9 MB
     |-- 磁盘 #0,分区 #2: GPT: Basic Data (GPT: 基本数据) Maj:Min=0:2, size: 126.6 GB @ C:
     |-- 磁盘 #0,分区 #3: GPT: Basic Data (GPT: 基本数据) Maj:Min=0:3, size: 845.2 MB @ G:
     \.PHYSICALDRIVE1: (model: WDC WD10SPCX-24HWST1 (标准磁盘驱动器) - S/N:      WD-WX31A86F35XC) size: 1.0 TB, reads: 379263 (6.0 GiB), writes: 103105 (2.6 GiB), xfer: 4014792 ms
     |-- 磁盘 #1,分区 #0: GPT: Basic Data (GPT: 基本数据) Maj:Min=1:0, size: 475.9 GB @ D:
     |-- 磁盘 #1,分区 #1: GPT: Basic Data (GPT: 基本数据) Maj:Min=1:1, size: 524.3 GB @ E:
    File System:
     File Descriptors: 0/0
     本地固定磁盘 (F:) (Fixed drive) [NTFS] 436.1 MiB of 450.0 MiB free (96.9%) is \?Volume{9afc85a4-9f44-11e7-ab77-a5dc01376557}  and is mounted at F:
     本地固定磁盘 (C:) (Fixed drive) [NTFS] 12.9 GiB of 117.9 GiB free (11.0%) is \?Volume{01a1a160-fbb4-49c7-be19-6dd52882bcbc}  and is mounted at C:
     本地固定磁盘 (G:) (Fixed drive) [NTFS] 303.4 MiB of 806.0 MiB free (37.6%) is \?Volume{9afc85a5-9f44-11e7-ab77-a5dc01376557}  and is mounted at G:
     本地固定磁盘 (D:) (Fixed drive) [NTFS] 161.8 GiB of 443.2 GiB free (36.5%) is \?Volume{a287f045-a9ac-4669-ab44-bdbd74692600}  and is mounted at D:
     本地固定磁盘 (E:) (Fixed drive) [NTFS] 246.0 GiB of 488.3 GiB free (50.4%) is \?Volume{84c6da35-38e7-457e-b528-c12da6ed2898}  and is mounted at E:
    Network interfaces:
     Name: wlan0 (Microsoft Wi-Fi Direct Virtual Adapter)
       MAC Address: 84:ef:18:36:4c:ab 
       MTU: 1500, Speed: 0 bps 
       IPv4: [] 
       IPv6: [fe80:0:0:0:55ed:790e:b70:ea43] 
       Traffic: received ?/?; transmitted ?/? 
     Name: net2 (Microsoft Teredo Tunneling Adapter)
       MAC Address: 00:00:00:00:00:00:00:e0 
       MTU: 1280, Speed: 100 Kbps 
       IPv4: [] 
       IPv6: [2001:0:9d38:6ab8:2446:2d3f:34a2:86f5, fe80:0:0:0:2446:2d3f:34a2:86f5] 
       Traffic: received 15 packets/2.2 KiB (0 err); transmitted 1580 packets/209.9 KiB (0 err) 
     Name: eth7 (Realtek PCIe GBE Family Controller)
       MAC Address: 54:ee:75:b0:ed:33 
       MTU: 1500, Speed: 0 bps 
       IPv4: [] 
       IPv6: [fe80:0:0:0:d0:cff0:250f:34d0] 
       Traffic: received ?/?; transmitted ?/? 
     Name: wlan2 (Intel(R) Dual Band Wireless-AC 3165)
       MAC Address: 84:ef:18:36:4c:aa 
       MTU: 1500, Speed: 72.2 Mbps 
       IPv4: [172.16.3.132] 
       IPv6: [] 
       Traffic: received 99670 packets/87.7 MiB (0 err); transmitted 68049 packets/14.9 MiB (0 err) 
    Network parameters:
     Host name: Sindrol-NTB
     Domain name: Sindrol-NTB
     DNS servers: [202.106.0.20, 114.114.114.114]
     IPv4 Gateway: 172.16.3.254
     IPv6 Gateway: ::
    Displays:
     Display 0:
      Manuf. ID=BOE, Product ID=65d, Digital, Serial=00000000, ManufDate=1/2015, EDID v1.4
      34 x 19 cm (13.4 x 7.5 in)
      Preferred Timing: Clock 141MHz, Active Pixels 1920x1080 
      Manufacturer Data: 000000000000000000000000000000000000
      Unspecified Text: BOE HF
      Unspecified Text: NV156FHM-N42
     Display 1:
      Manuf. ID=AOC, Product ID=2476, Digital, Serial=00000319, ManufDate=5/2016, EDID v1.3
      52 x 29 cm (20.5 x 11.4 in)
      Preferred Timing: Clock 148MHz, Active Pixels 1920x1080 
      Range Limits: Field Rate 50-76 Hz vertical, 30-83 Hz horizontal, Max clock: 170 MHz
      Monitor Name: 2476WM
      Serial Number: E71G5BA000793
    USB Devices:
     Intel(R) USB 3.0 可扩展主机控制器 - 1.0 (Microsoft) (通用 USB xHCI 主机控制器)
     |-- USB 根集线器(USB 3.0) ((标准 USB 集线器))
         |-- Apple Mobile Device USB Driver (Apple, Inc.)
             |-- Apple iPhone (Apple Inc.)
         |-- USB Composite Device ((标准 USB 主控制器))
             |-- Lenovo EasyCamera (Bison)
         |-- USB Composite Device ((标准 USB 主控制器))
             |-- USB 输入设备 ((标准系统设备))
                 |-- HID Keyboard Device ((标准键盘))
             |-- USB 输入设备 ((标准系统设备))
                 |-- HID-compliant mouse (Microsoft)
                 |-- 符合 HID 标准的供应商定义设备 ((标准系统设备))
                 |-- 符合 HID 标准的用户控制设备 (Microsoft)
                 |-- 符合 HID 标准的系统控制器 ((标准系统设备))
             |-- USB 输入设备 ((标准系统设备))
                 |-- 符合 HID 标准的供应商定义设备 ((标准系统设备))
         |-- USB 输入设备 ((标准系统设备))
             |-- HID-compliant mouse (Microsoft)
         |-- 英特尔(R) 无线 Bluetooth(R) (Intel Corporation)
  • 相关阅读:
    reduce端的连接实现
    Failed to stop mariadb.service: Interactive authentication required.
    Underlying cause: java.sql.SQLException : Access denied for user 'root'@'s150' (using password: YES)
    java.net.ConnectException: Call From s150/192.168.109.150 to s150:8020 failed on connection excepti
    启动hive出现 org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.ipc.StandbyExceptio
    hive learing_1
    在hive中执行sql语句:SemanticException org.apache.hadoop.hive.ql.metadata.HiveException:
    MariaDB [(none)]> drop user cr; ERROR 1396 (HY000): Operation DROP USER failed for 'cr'@'%'
    ThreadGroupAPI
    使用setUncaughtExceptionHandler在线程外面捕获异常
  • 原文地址:https://www.cnblogs.com/songxingzhu/p/9107878.html
Copyright © 2011-2022 走看看